Рисунок 4.5.3. Пример задания двух локальных массивов. Взят из отладчика IDA PRO.
Взгляните внимательно на Рисунок 4.5.3. Как видите, отладчик нам все прописал. Две переменные var_54 и var_28 являются, несомненно, массивами типа DWORD. Причем если на первый отводится 28h байт, т.е. 40 байт или 10 элементов массива, то на второй 54h-28h=2CH=44 или 11 элементов массива. И всего, следовательно, под локальные переменные зарезервировано 84 байта. А что означает команда add esp,0FFFFFFACH ? Но нас не обманешь! 0-0FFFFFFACH = 54h, что в десятичном исчислении и есть 84. В связи с массивами хотелось бы упомянуть, что в Си изначально практиковалось два способа доступа к элементам массива: посредством индексов и посредством указателей. Другими словами, можно было написать: a[i]=10 и *(a+i)=10. Причем вторая запись оказывалась более эффективной (см. по этому поводу книгу [1], гл. 15.). Разумеется, делать это можно и сейчас, но обе записи теперь в Borland C++ и Microsoft C++ 6.0 приводят к совершенно одинаковым ассемблерным эквивалентам. Что весьма отрадно - значит, компиляторы действительно развиваются. Кстати, весьма поучительным было бы сравнение ассемблерного кода, производимого разными компиляторами. Мы не будем этим заниматься, замечу только, что мое весьма поверхностное сравнение компиляторов Borland C++ 5.0 и Visual C++ 6.0 привело к выводу, что средства, разработанные фирмой Microsoft, несколько более эффективно оптимизируют транслируемый код.
Но вернемся опять к фрагменту на Рисунок 4.5.3. Посмотрим, как выглядит начало функции main в дизассемблере W32Dasm.
:00401108 55 push ebp :00401109 8ВЕС mov ebp, esp :0040110B 83C4AC add esp, FFFFFFAC :0040110E 53 push ebx :0040110F 33DB xor ebx, ebx