我有一个可变方法,我想将多个枚举值传递给:
typedef NS_ENUM(NSInteger,Enum){ Enum0 = 0, Enum1 = 1, Enum2 = 2, Enum3 = 3, Enum4 = 4, Enum5 = 5, …
您在参数列表末尾的零终止作为一个传递给您的函数 int (32位)值,但是你的 va_arg 拉开了 NSInteger (又名 long )堆栈中的值。所以你要从堆栈中抽出额外的32位,并将其全部视为一个64位值,其中一半是你想要的零,其中一半是在内存中与它相邻的任何内容。那时。
int
va_arg
NSInteger
long
您必须这样做才能获得所需的行为:
[var test:Enum1, Enum2, Enum3, Enum4, Enum5, Enum6, (NSInteger)0];
正如Rob Mayoff在下面的评论中所阐明的那样,将uncast零文字作为整数值视为一个 int 。正常的C整数提升规则适用*;在varargs列表中,因为参数没有声明的类型,所以较小的整数类型被提升为 - 并传递为 - int 秒。因为编译器无法看到您希望在运行时看到的实际类型,所以 int 不会被提升为 long 对你来说,因此在堆栈上卷起来 int 。
通常,varargs终止是隐式完成的( printf 风格预知arg数量和类型)或与常数一样 nil 这将是正确的宽度,这些方法避免了这个问题。在枚举值为的旧32位世界中 int S, 和 NSInteger 是 int ,默认的整数提升是 也 至 int ,这些区别是隐藏的。
printf
nil
实际上,这可能对您的代码设计意味着您可能会保留一个特殊的sentinel枚举值(不一定为零)来用作列表终止符以保证它的类型正确。或者您可能会修改以预先添加函数调用的参数数量。
*见C18标准搂6.3.1.1 ;-)
的 Bonus Explainer:你为什么看到价值 enum == 4294967296 ? 强>
enum == 4294967296
十进制数4294967296等于 0x0000000100000000 。第二个(下半部分)是你放在那里的32位零。上半部分看起来就像数字一样 1 。起初我假设这将是当前堆栈帧的其他(有效)部分,但是一些调查(在64位Mac上使用当前llvm和Xcode等)显示编译器设置调用 -test:... 通过推动enum args movq (移动quad = 64bit)和最终的零arg movl (移动长= 32位)。因为堆栈是64位对齐的,所以在倒数第二个和终端args之间的堆栈存储器中留下(即,不被覆盖)32位的“空洞”。这是包含的地方 0x1 。所以你不是在读一个相邻的参数,或者是有效但用于其他东西的其他值。您正在从某些早期函数调用的工作空间中读取ghost值。在我的调试中,它似乎不是来自alloc / init Variable - 它是先前的,与手头的测试代码无关。
0x0000000100000000
1
-test:...
movq
movl
0x1
Variable