Как память занята в этом куске кода? - PullRequest
2 голосов
/ 01 июля 2019

Я новичок в C и пытаюсь понять, как компилятор выполняет выделение памяти. Вот фрагмент кода, который я написал, чтобы понять, что происходит:

#include<stdio.h>
int main(void){
    int x=10;
    char y='A';
    printf("x: %p \ny: %p\n", &x, &y);
    return 0;
}

Выход:

x: 0x7fffcc33e10c
y: 0x7fffcc33e10b

Int занимает 4 байта, а Char занимает 1 байт. Так как же получается, что места, где хранятся эти переменные, являются последовательными? Я не могу этого понять.

Edit:

Как @Rup предложил в комментариях ниже, я попытался добавить в код больше целых чисел:

#include<stdio.h>
int main(void){
    int x=10;
    int m = 11;
    int n = 11;
    int o = 11;
    char y='A';
    printf("x: %p \nm: %p\nn: %p\no: %p\ny: %p\n", &x, &m, &n, &o, &y);
    return 0;
}

Я получил следующий вывод:

x: 0x7fff825c2e68
m: 0x7fff825c2e6c
n: 0x7fff825c2e70
o: 0x7fff825c2e74
y: 0x7fff825c2e67

пространство для y выделяется как 1 байт, а целые числа x, m, n, o - 4 байта. Спасибо за все ваши ответы.

Ответы [ 2 ]

5 голосов
/ 01 июля 2019

Распределение памяти для переменных целиком зависит от реализации - ответ будет зависеть от платформы к платформе.Переменные не обязательно должны быть расположены в том порядке, в котором они были объявлены, и в зависимости от требований выравнивания между концом одной переменной и началом другой могут быть «дыры» (неиспользуемые байты).

Вот что, вероятно, происходит в вашей системе (все байтовые значения в шестнадцатеричном формате):

   +----+
y: | 41 | 0x7fffcc33e10b    
   +----+
x: | 0a | 0x7fffcc33e10c    // assuming little-endian representation
   +----+
   | 00 | 0x7fffcc33e10d
   +----+
   | 00 | 0x7fffcc33e10e
   +----+
   | 00 | 0x7fffcc33e10f
   +----+

На x86 и аналогичных платформах стек растет «вниз» в сторону уменьшения адресов (x86 такжеlittle-endian, поэтому адресуемый байт является наименее значимым байтом многобайтового объекта).Таким образом, x выделяется «первым» по адресу 0x7fffcc33e10c, а затем y выделяется по следующему доступному адресу объекта.Поскольку y имеет char и ширину всего в один байт, следующий доступный адрес будет 0x7fffcc33e10b.Если бы y был также 4-байтовым int, то следующим доступным адресом был бы 0x7fffcc33e108, а расположение было бы примерно таким:

   +----+
y: | 41 | 0x7fffcc33e108
   +----+
   | 00 | 0x7fffcc33e109
   +----+
   | 00 | 0x7fffcc33e10a
   +----+
   | 00 | 0x7fffcc33e10b
   +----+
x: | 0a | 0x7fffcc33e10c    
   +----+
   | 00 | 0x7fffcc33e10d
   +----+
   | 00 | 0x7fffcc33e10e
   +----+
   | 00 | 0x7fffcc33e10f
   +----+

РЕДАКТИРОВАТЬ

Интересным упражнением было бы объявить

int x = 10;
char y = 'A';
int z = 20;

и посмотреть, как они выложены.Если они были размещены в объявленном порядке, то вы, вероятно, увидите один или несколько неиспользуемых байтов между y и z, поскольку большинству платформ требуются многобайтовые объекты для запуска по четному адресу.Я не удивлюсь, если компилятор решит выложить их как x, z, y, поскольку это сведет к минимуму любые такие "дыры".

РЕДАКТИРОВАНИЕ РЕДАКТИРОВАНИЯ

Попробовал сам, получил следующий результат:

       Item         Address   00   01   02   03
       ----         -------   --   --   --   --
          x  0x7ffee73b8a78   0a   00   00   00    ....

          y  0x7ffee73b8a77   41   0a   00   00    A...

          z  0x7ffee73b8a70   14   00   00   00    ....

Три неиспользованных байта между y и z, поэтому 4-байтовые объекты явно должны быть выровнены по адресам, кратным 4. Графически у нас есть

    +----+
z : | 14 | 0x7ffee73b8a70
    +----+ 
    | 00 | 0x7ffee73b8a71
    +----+
    | 00 | 0x7ffee73b8a72
    +----+
    | 00 | 0x7ffee73b8a73
    +----+
    | ?? | 0x7ffee73b8a74
    +----+
    | ?? | 0x7ffee73b8a75
    +----+
    | ?? | 0x7ffee73b8a76
    +----+
 y: | 41 | 0x7ffee73b8a77
    +----+
 x: | 0a | 0x7ffee73b8a78
    +----+
    | 00 | 0x7ffee73b8a79
    +----+
    | 00 | 0x7ffee73b8a7a
    +----+
    | 00 | 0x7ffee73b8a7b
    +----+
3 голосов
/ 01 июля 2019

Мой ответ не является точным или полным, поэтому для лучшего объяснения см. ответ Джона Боде .

Я добавил две дополнительные переменные:

#include<stdio.h>

int main(void){
    int x=10;
    char y='A';
    int z = 3;
    char m = 'a';
    printf("x: %p \ny: %p\nz: %p\nm: %p\n", &x, &y, &z, &m);
    return 0;
}

и вот вывод:

x: 0x7ffd2e8e0630 
y: 0x7ffd2e8e062e
z: 0x7ffd2e8e0634
m: 0x7ffd2e8e062f

Итак, я думаю, компилятор сначала выделяет char с, а затем int с.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...