0

为示例代码的 Objective-C 特性道歉,但我很确定我的问题的答案在 C 标准库和/或 Appleclang编译器中。

我有NSArray一个可变数量的项目。我想使用项目计数来创建一个介于 1 和 3 之间的值。我正在使用 CMAX宏,但它有一些奇怪的行为:

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上是 typedef'd to intand NSUIntegeris unsigned int。)

我很难理解原始代码中隐含的类型转换,导致我的结果不直观。有人可以照亮吗?

4

2 回答 2

2

3 - [tasks count] 使用无符号类型完成,因此减法环绕,变为 0xffffffff。所以你会得到无符号类型的 MAX(1, 0xffffffff) 。

但是,您将其打印为有符号整数,因为您的 NSLog 格式化字符串是“%d”,它将使 NSLog 将参数的位视为有符号整数,并且位模式 0xfffffff 为 -1。

于 2013-02-20T22:35:35.933 回答
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 中正确比较 anint和 an unsigned,但这不是您x > y在 C 中使用时得到的行为。相反,两个操作数都被转换为unsigned(由于“通常的算术转换”)。

因此,您的比较是(unsigned) 1 > (unsigned) -1,这是错误的,因为(unsigned) -1是最大的可能unsigned,这0xffffffff在大多数系统(32 位和 64 位)上都是如此。

错误在哪里?

NSLog(@"%d", [tasks count]);

这在技术上是错误的,您传递unsignedNSLog()但使用的是%d格式说明符 for int。改为使用%u,或将您的值转换为int第一个。

编译器警告

编译器会发出两个警告:

  • 可能会告诉您在计算时正在比较有符号和无符号MAX(1, 3 - [tasks count])

  • 当格式需要unsigned一个.NSLog()int

于 2013-02-20T22:36:36.087 回答