2013-08-14 3 views
-2
#include<stdio.h> 
struct krishna { 
     int i,j,k,l,m; 
    char c; 
    double d; 
    char g[48]; 
}; 
int main() { 
struct krishna *me={0}; 
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how?? 
return 0; 
} 

Привет всем Я новичок здесь и компилятор я использую GCC компилятор в коде выше может кто-нибудь объяснить, почемуповедение оператора sizeof?

1) указатель независимо от любого типа выделяется 8?

2) размер вышеуказанной структуры составляет 80? Может кто-нибудь объяснить мне в целом для любой структуры, как можно определить размер структуры, меня путают каждый раз, когда я ожидаю одно значение, но получаю другой ответ, и я также читал другие вопросы и ответы в переполнении стека по этому поводу, и я все еще не получая его. Пожалуйста, помогите.

+0

Ответ # 1: Нет. Размер указателя ** по определенной цели ** одинаковый для каждого типа. –

+0

cant get you mr @ RichardJ.RossIII –

+1

Размер указателя в соответствии со стандартами определяется реализацией. На практике размер указателя при компиляции для конкретной цели (в вашем случае, вероятно, x86_64) одинаковый, независимо от типа. Для другой цели (например, x86) вы можете получить другой размер указателя, например 4 (32 бита). –

ответ

3
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how?? 

На самом деле это должно быть:

printf("%zu %zu\n",sizeof(me),sizeof(*me));//output is 8 80 how?? 

"%zu" правильная строка формата для значения size_t, такие как значение, которое вы получаете от sizeof."%ld" может случиться с некоторыми системами (и, по-видимому, это делается на вас), но вы не должны рассчитывать на это.

Если ваш компилятор не поддерживает "%zu", вы можете использовать "%lu" (который ожидает unsigned long аргумента) и явно преобразовать аргументы:

printf("%lu %lu\n", (unsigned long)sizeof(me), (unsigned long)sizeof(*me)); 

Вы получаете 8 для sizeof(me) потому, что случается размер указателя на компиляторе, который вы используете (8 байт, 64 бит). Если вы скомпилировали и запустили свою программу в другой системе, вы можете получить 4, потому что многие системы имеют 32-разрядные указатели. (И это предполагает, что байт имеет 8 бит, что справедливо для большинства систем, но не гарантируется языком.)

Большинство компиляторов делают все указатели одинаковыми, но это не гарантируется также и языком. Например, на машине, адресованной слову, указатель int* может быть просто адресом машинного уровня, но указателю char* может понадобиться дополнительная информация, чтобы указать, какой байт находится в указанном слове. Вы вряд ли столкнетесь с системой с различными размерами указателей, но до сих пор нет смысла предполагать, что все указатели имеют одинаковый размер.

Что касается размера структуры, которая также может варьироваться от одного компилятора к другому. Вот ваша структура снова:

struct krishna { 
    int i,j,k,l,m; 
    char c; 
    double d; 
    char g[48]; 
}; 

char всегда точно 1 байт, и char[48] всегда ровно 48 байт.

Число байтов в int может варьироваться от одной системы к другой; В наши дни наиболее распространено 4 байта.

Размер double обычно занимает 8 байт, но это также может меняться (хотя я не думаю, что я когда-либо видел систему, где sizeof (double) не является 8 байт.)

члены Структура прокладываются в том порядке, в котором они объявлены, поэтому ваш i будет в самом начале структуры, а затем j, k и т. д.

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

Дело в том, что sizeof (struct krishna) составляет 80 байт в вашей системе не так уж и важно. Более важно понять (а) общие компиляторы правил, чтобы определить, как структурируются структуры, и (б) тот факт, что эти правила могут приводить к разным макетам для разных систем.

Определение языка и ваш компилятор гарантируют, что у вас могут быть объекты типа struct krishna и что вы можете получить доступ к этим объектам и их членам, возвращая все значения, которые вы сохранили в них. Если вам нужно знать, насколько велика struct krishna, ответ будет просто sizeof (struct krishna).Если по какой-то причине вам нужно знать более подробную информацию (например, если вам нужно сопоставить какой-то внешний шаблон), вы можете сделать некоторые эксперименты и/или проконсультироваться с документацией вашего компилятора, но имейте в виду, что будут применяться специфические особенности только для компилятора, который вы используете в системе, в которой вы его используете. (Часто ABI для вашей системы будет ограничивать выбор компилятора.)

Вы также можете использовать sizeof и offsetof (посмотреть его), чтобы выяснить, где выделяется каждый член.

+0

«Большинство компиляторов делают все указатели одинакового размера, но это тоже не гарантируется языком. Например, на текстовый адрес, указатель int * может быть просто адресом машинного уровня, но указателю char * может потребоваться дополнительная информация, чтобы указать, какой байт в пределах слова, на которое оно указывает. Вы вряд ли столкнетесь с системой с варьируя размеры указателей, но до сих пор нет смысла предполагать, что все указатели имеют одинаковый размер ». Можете ли вы объяснить этот параграф, это отличный ответ, который я получаю сейчас. Спасибо. –

+0

@ Krishnasundar: Я не уверен, что вы просите меня объяснить. Есть ли что-то особенное, что вы не понимаете? –

+0

В первой строке говорится, что компиляторы вид указателей отличаются от языка. ", но указателю char * может потребоваться дополнительная информация, чтобы указать, какой байт в слове он указывает на« вы имеете в виду массив символов здесь, и здесь вы говорите, что в этом случае я не изменяю свой указатель char *, не динамический. , так как эти утверждения относятся к предположению о том, что вы не принимаете все указатели на один размер, или lol я немного усложняю ситуацию Я получаю то, что вы сказали @Keith Thompson? –

3

Это потому, что:

sizeof(me) // is a pointer. 

... me является указателем. Размер указателя кратен слову в вашей среде, поэтому обычно в 32-битных средах указатель имеет 4 байта, тогда как в 64-битной среде указатель имеет 8 байтов (но не написан на камне). Если вы вернетесь через пару лет, 16-разрядная среда будет иметь указатель на 2 байта. Глядя на следующий sizeof:

sizeof(*me) // is a struct krishna, hence 80 bytes are needed to store it in memory. 

... это структура и размер структуры krishna составляет 80 байт. Если посмотреть на структуру:

struct krishna { 
    int i,j,k,l,m; // sizeof(int) * 5 
    char c; // sizeof(char) * 1 
    double d; // sizeof(double) * 1 
    char g[48]; // sizeof(char) * 48 
    // padding for memory address offset would be here. 
}; 

... если сложить количество байтов, необходимых для каждого поля и включить соответствующий data structure alignment адрес памяти смещения, то она составит 80 байт (как и ожидалось). Причина, по которой он добавляет дополнительные 3 неиспользуемых байта, заключается в том, что для хранения структуры в памяти он должен быть в непрерывном блоке памяти, который выделяется для структуры. По соображениям производительности он будет обрабатывать любые проблемы с размером, чтобы гарантировать, что адреса памяти всегда кратно слову. Компромисс между 3 байтами для повышения производительности стоит того, 3 байта в настоящее время не так сильно влияют на производительность, которую имеет процессор, когда обеспечивается согласование данных.

+1

И обратите внимание, что размер структуры равен 80, а не 77 из-за заполнения. После элемента 'c' будет 3 байта, так что двойные линии будут расположены на хорошей границе. –

+1

Говорить, что указатель является либо 4, либо 8 байтами ** неправильным **. Реализация определяется стандартом, и в то время как самые распространенные размеры на практике сегодня составляют 32 и 64 бита, исторически также были 16-битные системы, и другие модели тоже существуют. –

+0

@josh, я включил это уже, :), но справедливую точку (вы прокомментировали перед моим редактированием). –

3

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

Размер структуры зависит от того, как компилятор «упаковывает» отдельные поля структуры вместе в один блок памяти, чтобы содержать всю структуру. В вашем случае ваша структура имеет 5 полей int (по 4 байта каждая), одно поле char (1 байт), одно двойное поле (8 байтов) и массив из 48 символов. Добавьте все это, и вы получите 20 + 1 + 8 + 48 = 77 байт для хранения ваших данных. Фактический размер равен 80, потому что компилятор «заполняет» поле 1 байтового символа тремя дополнительными неиспользуемыми байтами, чтобы сохранить все поля в структуре, выровненные по 4-байтовому адресу памяти, что необходимо для хорошей производительности.

Надеюсь, что это поможет!

+0

можете ли вы объяснить, может повлиять на производительность в деталях, почему заполняется только для char –

+1

Большинство современных архитектур процессора оптимизированы для доступа к памяти на 4 байтовых границах. Убедившись, что все отдельные поля в вашей структуре находятся на границе 4 байта, это гарантирует, что любой код, который обращается к полю, будет быстрым. Если поле char не было заполнено, каждое поле после него не было бы на 4-байтовой границе и, следовательно, было бы медленнее для доступа. – ObjetDart

+1

На самом деле поле 1-байтового символа дополняется 8-байтовым выровненным адресом (удваивается 8 байтов). Но в этом случае это одно и то же, поскольку поле char находится в смещении 20, а следующий 8-байтовый выровненный адрес равен 24. Что фактически происходит при доступе к несогласованному объекту, так это то, что CPU загружает два правильно выровненных фрагмента памяти и отбрасывает нежелательный отдых. Следовательно, требуется как минимум вдвое больше времени, чем правильно выровненный доступ. По крайней мере - штраф может быть значительно выше в зависимости от аппаратного обеспечения. – cmaster

0

Чтобы добавить ответы на вопросы @Jacob Pollack и @ObjetDart, вы можете найти дополнительную информацию о структуре прокладки на Structure padding in C.

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