对示例代码的Objective-C性质表示歉意,但我非常确定我的问题的答案是在C标准库和/或Apple clang
编译器中。
我有一个NSArray
,其中包含可变数量的项目。我想使用项目计数来创建1到3之间的值。我正在使用C MAX
宏,但它有一些奇怪的行为:
NSLog( @"%d %d %d %d", 1, [tasks count], 3 - [tasks count], MAX( 1, 3 - [tasks count] ) );
当递增tasks
中的项目数时,此日志语句的输出是:
1 0 3 3
1 1 2 2
1 2 1 1
1 3 0 1
1 4 -1 -1
我稍微挖掘了一些文档,发现count
函数返回NSUInteger
。我的困境的解决方案是将返回值强制转换为NSInteger
:
NSLog( @"%d %d %d %d", 1, (NSInteger)[tasks count], 3 - (NSInteger)[tasks count], MAX( 1, 3 - (NSInteger)[tasks count] ) );
1 0 3 3
1 1 2 2
1 2 1 1
1 3 0 1
1 4 -1 1
(如果您不熟悉Objective-C,则在32位架构上NSInteger
对int
进行typedef,NSUInteger
为unsigned int
。< / p>
我正在努力理解我的原始代码中隐含发生的类型转换,导致我的不直观的结果。任何人都能发光吗?
答案 0 :(得分:2)
3 - [任务计数]是使用无符号类型完成的,因此减法包围,并变为0xffffffff。所以你得到MAX(1,0,0ffffffff)和无符号类型。
但是,您将其打印为有符号整数,因为您的NSLog格式化字符串是“%d”,它将使NSLog处理参数的位,因为它是一个带符号的int,并且位模式0xfffffff是-1
答案 1 :(得分:2)
打开编译器警告。如你所说,Objective C位是无关紧要的,所以我将从这里开始参考C.
假设您的MAX()
宏是以这种方式定义的(使用GCC扩展名):
#define MAX(x, y) ({ typeof (x) _x = (x); \
typeof (y) _y = (y); \
_x > _y ? _x : _y })
(MAX()
宏是非标准的
当您计算MAX(1, 3 - [tasks count])
时,您会得到:
int x = 1;
unsigned y = 3 - [tasks count];
x > y ? x : y;
现在,可以正确比较C中的int
和unsigned
,但这不是在C中使用x > y
时获得的行为。相反,两个操作数都被转换至unsigned
(由于“通常的算术转换”)。
所以你的比较是(unsigned) 1 > (unsigned) -1
,这是假的,因为(unsigned) -1
是最大的unsigned
,在大多数系统上都是0xffffffff
(32位和64位)
NSLog(@"%d", [tasks count]);
这在技术上是错误的,您将unsigned
传递给NSLog()
,但使用的%d
格式说明符适用于int
。请改用%u
,或先将值转换为int
。
编译器将发出两个警告:
可能会告诉您在计算MAX(1, 3 - [tasks count])
时正在将签名与未签名人进行比较。
当格式需要unsigned
时,它会告诉您正在将NSLog()
传递给int
。