Ваше нулевое завершение в конце списка аргументов передается вашей функции как int
(32-битное) значение, но ваше va_arg
вытягивает значение NSInteger
(иначе long
)из стека.Таким образом, вы извлекаете дополнительные 32 бита из стека и смотрите на все это как на одно 64-битное значение, половина которого - это ноль, который вы намеревались, а половина - то, что произошло рядом с ним в памяти.в этот раз.
Вы должны были бы сделать это, чтобы получить поведение, которое вы хотите:
[var test:Enum1, Enum2, Enum3, Enum4, Enum5, Enum6, (NSInteger)0];
Как поясняет Роб Мейофф в комментариях ниже, лицевой нулевой литерал, являющийся целочисленным значением,трактуется как int
.Применяются обычные целочисленные правила продвижения C *;в списке varargs, поскольку аргументы не имеют объявленного типа, более целочисленные типы повышаются до - и передаются как - int
s.Поскольку компилятор не имеет представления о реальных типах, которые вы ожидаете увидеть во время выполнения, то int
не будет преобразован в long
для вас, поэтому он попадает в стек как int
.
Как правило, завершение varargs выполняется либо неявно (предвидение стиля printf
числа и типов arg), либо с константой, подобной nil
, которая будет правильной ширины, и эти подходы позволяют избежать этой проблемы.В старом 32-битном мире, где значения enum были int
s, и NSInteger
были int
, а целочисленное продвижение по умолчанию было , а также до int
, этиразличия были скрыты.
На практике это может означать для вашего дизайна кода то, что вы, возможно, зарезервировали бы специальное значение перечисления часового (не обязательно равное нулю), чтобы использовать его в качестве ограничителя списка, чтобы гарантировать, что он имеет правильный тип.Или вы, возможно, измените, добавив число аргументов к вызову функции.
* См. Стандарт C18 §6.3.1.1 ;-)
Объяснитель бонуса: Почему вы увидели значение enum == 4294967296
?
Десятичное число 4294967296 равно 0x0000000100000000
.Вторая (нижняя) половина этого значения была 32-битным нулем, который вы поставили туда.Верхняя половина выглядит так, как будто это просто число 1
.Сначала я предположил, что это будет какая-то другая (действительная) часть текущего стекового фрейма, но некоторые исследования (на 64-битном Mac с использованием текущего llvm с Xcode и т. Д.) Показывают, что компилятор устанавливает вызов -test:...
путем нажатия на enum args с помощью movq
(move quad = 64bit) и конечного нулевого arg с movl
(move long = 32bit).Поскольку стек выровнен на 64 бита, в стеке памяти между предпоследним и конечным аргументами остается «дыра» в 32 бита (т.е. не перезаписывается).Это место, которое содержало 0x1
.Таким образом, вы не читаете соседний аргумент или другое значение, которое является допустимым, но используется для чего-то другого.Вы читаете призрачное значение из рабочего пространства вызова более ранней функции.В моей отладке, это не похоже на alloc / init Variable
- это что-то предшествующее и не связанное с тестовым кодом под рукой.