Извините, но в этом куске кода абсолютно ничего умного, и люди, которые его используют, очень глупы.
Приложение:
Или, иногда, иногда очень умный.Посмотрев видео, на которое ссылается обновление вопроса, это не какая-то мошенническая обезьяна, нарушающая правила.Этот парень хорошо понимал, что он делает.
Требуется глубокое понимание сгенерированного кода и он может легко сломаться (как упоминалось и видно здесь), если ваша среда меняется (например, компиляторы, архитектуры и т. Д.).
Но, если у вас есть это знание, вам, вероятно, это сойдет с рук.Это не то, что я бы предложил никому, кроме ветеранов, но я вижу, что это имеет место в очень ограниченных ситуациях, и, честно говоря, я, несомненно, иногда был несколько более ... прагматичным ..., чем следовало быбыл в моей карьере: -)
Теперь вернемся к вашему обычному программированию ...
Это непереносимо между архитектурами, компиляторами, выпусками компиляторов и, возможно,даже уровни оптимизации в одной и той же версии компилятора, а также неопределенное поведение (чтение неинициализированных переменных).
Лучше всего, если вы хотите понять, что это - проверять код ассемблера, выводимый компилятором.
Но в целом вам лучше всего забыть об этом и написать код стандарта.
Например, эта транскрипция показывает, как 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
расположение его локальных переменных (включая любые временные значения, не явно созданные разработчиком), и у вас возникнет эта проблема.