Ваше нулевое завершение в конце списка аргументов передается вашей функции как int
(32-битное) значение, но ваш va_arg
вытягивает значение NSInteger
(он же long
) из стека. Таким образом, вы извлекаете дополнительные 32 бита из стека и смотрите на все это как на одно 64-битное значение, половина которого - это ноль, который вы намеревались, а половина - то, что произошло рядом с ним в памяти. в то время.
Вы должны сделать это, чтобы получить желаемое поведение:
[var test:Enum1, Enum2, Enum3, Enum4, Enum5, Enum6, (NSInteger)0];
Как поясняет Роб Мейофф в комментариях ниже, литерал с нулевым нулем, являющийся целочисленным значением, рассматривается как [115 ]. Применяются обычные целочисленные правила продвижения C *; в списке varargs, поскольку аргументы не имеют объявленного типа, более целочисленные типы повышаются до - и передаются как - int
с. Поскольку компилятор не имеет представления о фактических типах, которые вы ожидаете увидеть во время выполнения, этот int
не будет повышен до long
для вас, поэтому он попадает в стек как int
.
Как правило, завершение varargs выполняется либо неявно (предвидение стиля printf
числа и типов arg), либо с константой, подобной nil
, которая будет правильной ширины, и эти подходы позволяют избежать этой проблемы. В старом 32-битном мире, где значения enum были int
с, и NSInteger
были int
, и целочисленное продвижение по умолчанию было , также - int
, эти различия были скрыты.
На практике это может означать для вашего дизайна кода то, что вы, возможно, зарезервировали бы специальное значение перечисления (не обязательно ноль), чтобы использовать его в качестве ограничителя списка, чтобы гарантировать, что он имеет правильный тип. Или вы, возможно, измените, добавив число аргументов к вызову функции.
* См. Стандарт C18 §6.3.1.1 ;-)
Объяснитель бонуса: почему вы увидели значение enum == 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
- это что-то предшествующее и не связанное с тестовым кодом под рукой.
Вам больше не следует использовать onClick
, если вы используя jQuery. jQuery предоставляет свои собственные методы присоединения и привязки событий. См. .click ()
$(document).ready(function(){
var js = "alert('B:' + this.id); return false;";
// create a function from the "js" string
var newclick = new Function(js);
// clears onclick then sets click using jQuery
$("#anchor").attr('onclick', '').click(newclick);
});
. Это должно отменить функцию onClick
- и также сохранить ваш «javascript from a string».
Лучше всего будет удалить onclick = ""
из элемента
в коде HTML и переключитесь на использование ненавязчивого метода для привязки события к щелчку.
Вы также сказал:
Используя
onclick = function () {return eval (js); }
не работает, потому что вы не можете использовать return в коде, переданном в eval ().
Нет - не будет, но onclick = eval ("(function () {" + js + "})");
перенесет переменную 'js' в оболочку функции. onclick = new Function (js);
также работает и немного чище для чтения. (обратите внимание на заглавную F) - см. документацию по конструкторам Function ()
просто используйте метод привязки jQuery! Jquery-selector ! .bind ('event',! fn!);
Одна хитрость с Jquery заключается в том, что функция щелчка не распознает нажатие, закодированное вручную, из html.
Итак, вам в значительной степени придется выбирать. Установите все ваши обработчики в функции init или все они в html.
Событием click в JQuery является функция щелчка $ ("myelt"). Click (function ....).
Если вы не хотите фактически переходить к новому вы также можете разместить свой якорь где-нибудь на странице, как здесь.
<a id="the_anchor" href="">
А затем, чтобы назначить вашу строку JavaScript для onclick привязки, поместите это где-нибудь в другом месте (то есть в заголовок, позже в теле, что угодно):
<script>
var js = "alert('I am your string of JavaScript');"; // js is your string of script
document.getElementById('the_anchor').href = 'javascript:' + js;
</script>
Если у вас есть вся эта информация на сервере перед отправкой страницы, вы также можете просто поместить JavaScript прямо в атрибут href
привязки, например:
<a href="javascript:alert('I am your script.'); alert('So am I.');">Click me</a>
Придумал быстрое и грязное решение этой проблемы. Только что использовано
Hope это помогает
Кстати, без JQuery это тоже можно было бы сделать, но, очевидно, это довольно некрасиво, поскольку рассматривается только IE / не-IE:
if(isie)
tmpobject.setAttribute('onclick',(new Function(tmp.nextSibling.getAttributeNode('onclick').value)));
else
$(tmpobject).attr('onclick',tmp.nextSibling.attributes[0].value); //this even supposes index
В любом случае, просто чтобы люди имели общее представление о том, что можно сделать, поскольку я уверен, что многие сталкивались с этим раздражением.
Note that following gnarf's idea you can also do:
var js = "alert('B:' + this.id); return false;";<br/>
var newclick = eval("(function(){"+js+"});");<br/>
$("a").get(0).onclick = newclick;
That will set the onclick without triggering the event (had the same problem here and it took me some time to find out).