C无符号整数减法,宏和类型转换

时间:2013-02-20 22:25:47

标签: c casting macros

对示例代码的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位架构上NSIntegerint进行typedef,NSUIntegerunsigned int。< / p>

我正在努力理解我的原始代码中隐含发生的类型转换,导致我的不直观的结果。任何人都能发光吗?

2 个答案:

答案 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中的intunsigned,但这不是在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