2016-11-19 5 views
2

У меня есть вопрос по поводу ответа отСмущайтесь насчет адреса адреса

@ dan04. What is aligned memory allocation?

В частности, если у меня есть что-то вроде этого:

int main(){ 
     int num; // 4byte 
     char s; // 1byte 
     int *ptr; 


} 

Если у меня есть 32 битной машине, вы думаете, он все равно будет набивка на данные по умолчанию?

В предыдущем вопросе было задано вопрос о struct, и я задаю вопрос о переменных, объявленных в main.

обновление:

a = 2 bytes 
b = 4 bytes 
c = 1 byte 
d = 1 byte 



0 1 2 3 4 5 6 7 
|a|a|b|b|b|b|c|d| bytes 
|  |  | words 
+0

Указатели также нуждаются в хранении памяти. – ForceBru

+0

Почему, по-вашему, эти переменные хранятся где угодно? Это автоматические переменные, и они могут быть оптимизированы или доступны только в регистрах. Более того, если он когда-либо хранится в памяти, компилятор может переупорядочить их, если он сочтет это полезным и т. Д. – Walter

ответ

5

Там нет никаких правил для этого. Это зависит от используемой вами реализации. Далее он может меняться в зависимости от параметров компилятора. Лучшее, что вы можете сделать, это напечатать адрес каждой переменной. Затем вы можете увидеть, как выглядит макет памяти.

Что-то вроде этого:

int main(void) 
{ 
    int num; 
    char s; 
    int *ptr; 

    printf("num: %p - size %zu\n", (void*)&num, sizeof num); 
    printf("s : %p - size %zu\n", (void*)&s, sizeof s); 
    printf("ptr: %p - size %zu\n", (void*)&ptr, sizeof ptr); 

    return 0; 
} 

Возможный выход:

num: 0x7ffee97fce84 - size 4 
s : 0x7ffee97fce83 - size 1 
ptr: 0x7ffee97fce88 - size 8 

заметить также, что в случае, если вы не принимаете адрес (&) переменной, компилятор может оптимизировать код так что переменная никогда не помещается в память.

В целом, выравнивание обычно выполняется для получения наилучшей производительности из используемой платформы HW. Это, как правило, означает, что переменные выровнены с их размером или, по меньшей мере, 4 байта выровнены для переменных с размером больше, чем 4.

Обновление:

ОП дает конкретный пример компоновки в обновлении и спрашивает, если этот макет может/когда-либо случится.

Опять ответ: Это зависит от реализации

Так что в принципе это может произойти на какой-то конкретной системе. Тем не менее я сомневаюсь, что это произойдет в любой основной системе.

Существует еще один пример кода, составленный с НКУ -O3

int main(void) 
{ 
    short s1; 
    int i1; 
    char c1; 
    int i2; 
    char c2; 


    printf("s1: %p - size %zu\n", (void*)&s1, sizeof s1); 
    printf("i1: %p - size %zu\n", (void*)&i1, sizeof i1); 
    printf("c1: %p - size %zu\n", (void*)&c1, sizeof c1); 
    printf("i2: %p - size %zu\n", (void*)&i2, sizeof i2); 
    printf("c2: %p - size %zu\n", (void*)&c2, sizeof c2); 

    return 0; 
} 

Выход из моей системы:

s1: 0x7ffd222fc146 - size 2 <-- 2 byte aligned 
i1: 0x7ffd222fc148 - size 4 <-- 4 byte aligned 
c1: 0x7ffd222fc144 - size 1 
i2: 0x7ffd222fc14c - size 4 <-- 4 byte aligned 
c2: 0x7ffd222fc145 - size 1 

Обратите внимание, как расположение в памяти отличается от переменных порядка был определен в код. Это обеспечивает хорошее выравнивание.

Сортировка по адресу:

c1: 0x7ffd222fc144 - size 1 
c2: 0x7ffd222fc145 - size 1 
s1: 0x7ffd222fc146 - size 2 <-- 2 byte aligned 
i1: 0x7ffd222fc148 - size 4 <-- 4 byte aligned 
i2: 0x7ffd222fc14c - size 4 <-- 4 byte aligned 

Итак, еще раз, чтобы ответить на ДОПОЛНЕНО вопрос:

В большинстве систем я сомневаюсь, что вы будете видеть переменную с 4 байт помещаются по адресу xXx2, xxx6 или xxxa , xxxe. Но все же могут существовать системы, где это может произойти.

+0

Я имею в виду, почему в ссылке люди говорят, что граница будет 4 байта? –

+0

@Anni_housie Ну, это связано с аппаратной архитектурой. Например, кеш обычно организован в строках с 2^N байтами. Для производительности было бы плохо, если бы 4 байтовая переменная имела два байта в одной строке кэша и следующие два байта в следующей строке кэша. Поэтому мы обычно хотим, чтобы 4 байтовые переменные были выровнены по 4 байт, чтобы переменная могла удерживаться в отдельной строке кеша. Это всего лишь один пример - их больше. Но опять же - это зависит от реализации – 4386427

+0

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

1

Трудно точно предсказать, но, конечно же, происходит прокладка. Возьмите эти два кода, например (я запускать их на Coliru, 64-битной машине)

#include<iostream> 
#include <vector> 
using namespace std; 

//#pragma pack(push,1) 
int main(){  
     int num1(5); // 4byte 
     int num2(3); // 4byte 
     char c1[2]; 
     c1[0]='a'; 
     c1[1]='a'; 
     cout << &num1 << " " << &num2 << " " << endl;  
     cout << sizeof(c1) << " " << &c1 << endl; 

} 
//#pragma pack(pop) 




    #include<iostream> 
#include <vector> 
using namespace std; 

//#pragma pack(push,1) 
int main(){  
     int num1(5); // 4byte 
     int num2(3); // 4byte 
     char c1[1]; 
     c1[0]='a'; 
     cout << &num1 << " " << &num2 << " " << endl;  
     cout << sizeof(c1) << " " << &c1 << endl; 

} 
//#pragma pack(pop) 

Первые результаты программы:

0x7fff3e1f9de8 0x7fff3e1f9dec 
2 0x7fff3e1f9de0 

Хотя вторая программа выходов:

0x7fffdca72538 0x7fffdca7253c 
1 0x7fffdca72537 

You может определенно заметить, что в первой программе есть дополнение, просматривающее адреса, которые мы видим: Первая программа: CHAR | CHAR | 6-БЕЙТ-ПАДДИНГ | INT | INT Вторая программа: CHAR | INT | INT

Итак, по базовому вопросу, да, возможно, по умолчанию это дополнение. Я также пытался использовать пакет pragma, чтобы избежать заполнения, и, в отличие от случая структуры, мне не удалось избежать заполнения, так как выходы были точно такими же.

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

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