Вам интересно, как C выделяет память для массива ... и других типов данных. ХОРОШО. Ну, это зависит от того, как определяется массив (или другая переменная). В вашем случае вы определили их как автоматически размещаемые («локальные») переменные, поэтому они хранятся в стеке времени выполнения C. (Технически может существовать другой механизм распределения для переменных с автоматическим хранением, но на практике большинство систем используют стек времени выполнения.) Если вы определили массив и другие переменные на несколько строк выше int main(void)
, они будут «глобальными переменными». "и будет размещен статически и с внешней связью, чтобы они были видны другим модулям компиляции (другим файлам .c). И если вы поставите перед ними ключевое слово static
, они все равно будут размещены статически, но их связь будет внутренней, поэтому они не будут видны другим модулям компиляции (файлы .c). Последняя часть верна независимо от того, определяете ли вы переменные внутри или снаружи тела функции;если вы определите их как static
вне тела функции, они будут доступны для других функций в том же модуле компиляции;если вы определяете их как static
внутри тела функции, компилятор разрешает доступ к ним только одной функции;на самом деле они видны только в той области, в которой они определены.
Что касается того, где именно они размещены, компилятор / компоновщик может свободно размещать их в любом месте области своего класса хранения, в которой он находится. выбирает;в этом случае компилятор помещает их в стек времени выполнения, но их порядок и относительное расположение не определяются языком, поэтому компилятор может размещать их любым удобным для него способом.
Часто переменныебыть распределенными между ними, чтобы гарантировать их выравнивание, чтобы они начинали с оптимальной границы для своего размера данных, потому что (из-за проблем с оборудованием) часто быстрее получить доступ к данным на границах байтов, которые соответствуют их ширине данных, что точночто тут происходит. Вы можете сказать: «Но i
заканчивается на 4-байтовой границе, а a[]
не имеет требований к выравниванию, так почему он добавил дополнение после i
до того, как выделил a[]
?»Но это потому, что вы думаете о распределении, происходящем в порядке увеличения адреса памяти. Вы заметили, что, похоже, ваши переменные расположены в памяти "задом наперед"? На самом деле это не так! В большинстве систем стек увеличивается в памяти от высоких адресов к низким адресам. Имея это в виду, ясно, что первая переменная из вашего набора переменных, которая была выделена, - a[]
, за которой следует i
(по более низкому адресу). Поскольку адрес байта, следующий за a[]
, не был кратен 4, перед тем, как компилятор выделил i
, он добавил 2 байта заполнения!
Теперь, что касается значений, которые вы читаете в 0x0028FF34 и 0x0028FF35: Что бы там ни было, остался только мусор от того, что было в последний раз записано на эти адреса. Байт в 0x0028FF34 равен 0x80, который передается в 'printf ()' через ...
varargs как целое число, а в вашей системе char
должен быть подписан, поэтому, когда он преобразуется в целое число, он расширяется до знака, и посколькустарший бит 0x80 равен 1, результирующее значение равно 0xFFFFFF80. Целое число, которое вы прочитали как 0x0028FF35, показывает, что байт по этому адресу равен 0x00, а остальные байты - это 03, 02 и 01, и вы должны заметить, что это первые 3 байта a[]
. Исходя из этого, мы также можем сказать, что ваша система имеет младший порядок (например, x86), так как старший байт целого числа находится в старшей адресуемой байтом позиции.