Ответ 1
Извините, но в этом фрагменте кода нет ничего умного, и люди, которые его используют, очень глупы.
Приложение:
Или, иногда, иногда, очень умно. Посмотрев видео, связанное с обновлением вопроса, это была не какая-то обезьяна-мошенник, нарушающая правила. Этот парень понял, что он делает хорошо.
Это требует глубокого понимания генерируемого кода и может легко сломаться (как упоминалось и видно здесь), если ваша среда изменяется (например, компиляторы, архитектуры и т.д.).
Но, если у вас есть это знание, вы, вероятно, можете уйти от него. Это не то, что я предлагаю никому, кроме ветерана, но я вижу, что он имеет свое место в очень ограниченных ситуациях и, честно говоря, я, без сомнения, был несколько более... прагматичным... чем я должен был бы был в моей собственной карьере: -)
Теперь вернемся к вашему регулярному программированию...
Он не переносится между архитектурами, компиляторами, версиями компиляторов и, возможно, даже уровнями оптимизации в пределах одной и той же версии компилятора, а также является undefined поведение (чтение неинициализированных переменных).
Лучше всего, если вы хотите понять, что он должен проверить код ассемблера, выводимый компилятором.
Но ваш лучший выбор в целом - это просто забыть об этом и привести к стандарту.
Например, этот транскрипт показывает, как gcc может иметь различное поведение на разных уровнях оптимизации:
pax> gcc -o qq qq.c ; ./qq
0
1
2
3
4
5
6
7
8
9
pax> gcc -O3 -o qq qq.c ; ./qq
1628373048
1629343944
1629097166
2280872
2281480
0
0
0
1629542238
1629542245
В gcc высокий уровень оптимизации (что мне нравится называть его безумным уровнем оптимизации), это функция makeArray
. В основном выяснилось, что массив не используется и поэтому оптимизировал свою инициализацию из существования.
_makeArray:
pushl %ebp ; stack frame setup
movl %esp, %ebp
; heavily optimised function
popl %ebp ; stack frame tear-down
ret ; and return
На самом деле я немного удивлен, что gcc даже оставил там заглушку функции.
Обновление: как отмечает Николя Рыцарь в комментарии, функция остается, так как она должна быть видна компоновщику, что делает статическую функцию функцией gcc также удалением заглушки.
Если вы проверите код ассемблера на уровне оптимизации 0 ниже, он дает ключ (это не фактическая причина - см. ниже). Изучите следующий код, и вы увидите, что установка фрейма стека отличается для двух функций, несмотря на то, что они имеют точно такие же параметры, что и в тех же локальных переменных:
subl $48, %esp ; in makeArray
subl $56, %esp ; in printArray
Это связано с тем, что printArray выделяет дополнительное пространство для хранения адреса строки формата printf
и адреса элемента массива, по четыре байта, который учитывает разницу в восьми байтах (два 32-разрядных значения).
Это наиболее вероятное объяснение для вашего массива в printArray()
отключено двумя значениями.
Здесь две функции на уровне оптимизации 0 для вашего удовольствия: -)
_makeArray:
pushl %ebp ; stack fram setup
movl %esp, %ebp
subl $48, %esp
movl $0, -4(%ebp) ; i = 0
jmp L4 ; start loop
L5:
movl -4(%ebp), %edx
movl -4(%ebp), %eax
movl %eax, -44(%ebp,%edx,4) ; array[i] = i
addl $1, -4(%ebp) ; i++
L4:
cmpl $9, -4(%ebp) ; for all i up to and including 9
jle L5 ; continue loop
leave
ret
.section .rdata,"dr"
LC0:
.ascii "%d\12\0" ; format string for printf
.text
_printArray:
pushl %ebp ; stack frame setup
movl %esp, %ebp
subl $56, %esp
movl $0, -4(%ebp) ; i = 0
jmp L8 ; start loop
L9:
movl -4(%ebp), %eax ; get i
movl -44(%ebp,%eax,4), %eax ; get array[i]
movl %eax, 4(%esp) ; store array[i] for printf
movl $LC0, (%esp) ; store format string
call _printf ; make the call
addl $1, -4(%ebp) ; i++
L8:
cmpl $9, -4(%ebp) ; for all i up to and including 9
jle L9 ; continue loop
leave
ret
Обновление: как отмечает Родди в комментарии. это не причина вашей конкретной проблемы, так как в этом случае массив фактически находится в одном и том же положении в памяти (%ebp-44
с %ebp
одинаково для двух вызовов). То, что я пытался указать, состояло в том, что две функции с одним и тем же списком аргументов и с теми же локальными параметрами не обязательно совпадают с одинаковой компоновкой фрейма.
Все, что понадобилось бы для printArray
, чтобы поменять местами локальные переменные (включая любые временные разделы, явно не созданные разработчиком), и у вас возникнет такая проблема.