2013-03-24 1 views
4

Я прочитал, что функции в C могут использовать локальные переменные на основе стека, и они распределяются просто путем уменьшения указателя стека на требуемое пространство. Это всегда делается в четырехбайтовых кусках (если я не ошибаюсь). Но, что если запустить код, как следующее:Какое пространство памяти занято авто переменными в стеке

void foo(void) 
{ 
    char str[6]; 
    ...... 
} 

Какой размер не вар str занимают? 6 байтов или 6 × 4 байтов в соответствии с четырьмя байтовыми кусками.

ответ

2

Правило с четырьмя байтами просто означает, что указатель стека должен указывать на адрес, который кратен четырем. В этом случае выделение 8 байтов удовлетворяет этому правилу, и такой блок достаточно велик, чтобы содержать 6-значный массив с двумя байтами заполнения.

0

Я предполагаю, что вы путаетесь между Размер данных и выравнивание данных. Нет общего правила, но на современных компьютерах ваша переменная будет храниться в 6 байтах. С другой стороны, следующий элемент не обязательно будет храниться в следующем байте. Это известно как заполнение структуры данных.

архитектуры с нулевыми значениями, где каждая переменная должна начинаться с адреса, который кратен размеру слова, становятся редкими. С новыми процессорами, такими как SPARC или x86, переменными являются самовыравнивающиеся. Это означает, что они должны начинаться с адреса, который кратен его размеру типа.

Таким образом, на неэкзотических компьютерах не существует «правила с четырьмя байтами». В вашем примере str будет храниться с 6 байтами. Если вы объявляете переменную с выравниванием 8 байтов (например, double на x86), будет добавлено 2 байта заполнения, вставленных вашим компилятором.

Выравнивание фиксируется компилятором в соответствии с вашей архитектурой. Поэтому стандарт ничего не определяет об этом. Вы можете найти дополнительную информацию по Wikipedia.

0

Правило распределения в 4-байтовых кусках недействительно во всех случаях. Например, ARM eabi требует алиментации 64-битных целых чисел и удвоений на 8-байтных границах.

Обычно выделенное пространство соответствует правилам упаковки данных в структуры. Таким образом, char[6] фактически займет 6 байтов (обычно), но заполнение данных (для следующего поля) может использовать несколько байтов больше.

Пример:

struct X 
{ 
    char field1[6]; 
}; 

Так размерная структура X будет 8

structure Y 
{ 
    char field1[2]; 
    double field2; 
}; 

Структура Y обычно что-то вроде 8, 12 или 16 байт в зависимости от архитектуры.

Те же правила применяются к автоматическим переменным стека: обычно заполнение продиктовано не типом, который вы используете, а следующим типом, который вы собираетесь использовать. И правила иногда немного расплывчаты.

+0

Можно заставить компилятор не вставлять ваши структуры данных, хотя, насколько я понимаю, это приведет к потере производительности. – 2013-03-24 17:05:10

+0

@dingrite Некоторые компиляторы позволяют определить определенные атрибуты данных в стеке. Но это исключение, поскольку правила определяются документацией на платформе и делают части приложения несовместимыми со стандартной библиотекой и другим существующим кодом. –

+0

@dingrite Я забыл упомянуть упакованные структуры. Вы можете использовать их, но побочные эффекты и ограничения переносимости могут привести к снижению веса. –

2

Согласование данных - это требование к процессору, что означает, что величина выравнивания изменяется от CPU к другому, помните об этом.

Говоря о выравнивании данных стека, например, gcc поддерживает выравнивание данных с использованием параметра, называемого -mpreferred-stack-boundary=n, где данные будут выровнены с 2^n. По умолчанию значение n равно 4, что делает выравнивание стека 16-байтами.

Это означает, что вы обнаружите, что выделяете 16 байтов в стеке, хотя то, что вы явно выделили, было целым числом.

int main() 
{ 
     char ar[6] = {1,2,3,4,5,6}; 
     int x = 10; 
     int y = 12 + (int) ar[1] + x; 
     return y; 
} 

Компиляция кода с GCC на моем CPU производит последующую сборку (проводки только инструкции стека распределение):

subl $32, %esp 

Но почему 32? мы выделяем данные, которые точно соответствуют 16 байтам. Ну, есть 8 байт НКУ должны держать сохраненные для leave и ret, что делает общую память, необходимой 24
НО, требование выравнивания составляет 16 байт и, таким образом, ССАГПЗА потребности выделить стек-пространство таким образом, что это сделано до 16-байтовых кусков; что 24 байта до 32 решает проблему.
У вас будет достаточно места для ваших переменных, для ret и leave, и он состоит из двух 16-байтовых кусков.

0

Если у вас есть:

char str[6]; 
int a; 
char b; 
char c; 

Стек будет иметь достаточный размер, чтобы вместить все эти переменные и делится на 4 (или что-то выравнивание не требуется). Но каждая переменная не должна быть выровнена на одной границе (хотя могут быть аппаратные требования).

В моей системе компиляции выше и распечатывания адреса переменных стека (начальные цифры удалены для краткости):

&str -- 18 
&a  -- 12 
&b  -- 10 
&c  -- 11 

т.е. компилятор устроят для стека быть выровнены, а переменные не нужно дополнять.

 Смежные вопросы

  • Нет связанных вопросов^_^