2010-09-16 4 views
6

Я не понимаю, почемуРазмер структуры с двумя указателями void равен 4?

struct e{ 
    void * a; 
    void * b[]; 
} 

имеет SizeOf (е) == 4, а

struct f{ 
    void * a; 
    void * b; 
} 

имеет SizeOf (F) == 8.

+0

[обсуждение законности «структурного взлома» в ansi c] (http://stackoverflow.com/questions/3711233/). Поиск на «struct hack» on So не возвращает большой интерес прямо сейчас, но это фраза, которую вы ищете. – dmckee

ответ

12

Второй в первой структуре не является указателем, а FAM - гибким элементом массива. Он используется, когда у вас длинный буфер и помещается e в начале этого буфера. Затем вы можете проиндексировать оставшуюся память, которая следует за объектом e, используя эту FAM и обрабатывать эту память как массив из void*.

Стандарт говорит (акцент мной)

Как частный случай, последний элемент структуры с более чем одним именем элемента может иметь неполный тип массива; это называется гибким элементом массива. В большинстве ситуаций элемент гибкого массива игнорируется. В частности, размер структуры выглядит так, как если бы отсутствовал гибкий элемент массива , за исключением того, что он мог иметь более длинную прокладку, чем .

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

struct A { 
    char a; 
}; 

struct B { 
    char a; 
    int flex[]; 
}; 

int main() { 
    printf("sizeof A: %d\nsizeof B: %d\n", 
     (int)sizeof(struct A), 
     (int)sizeof(struct B) 
    ); 

    struct B *b = malloc(sizeof *b + sizeof(int[3])); 
    b->a = 'X'; 
    b->flex[0] = 1; 
    b->flex[1] = 2; 
    b->flex[2] = 3; 
    free(b); 
} 
+0

Поскольку вы собрали содержимое в различных сообщениях и добавили пример, я принял ваш ответ по сравнению с предыдущим. –

17
struct e{ 
    void * a; 
    void * b[]; 
//   ^^ 
} 

[] в struct делает b членом гибкой матрицы C99. Таким образом, sizeof(e) будет рассчитывать размер только a, который 4.

От C99 § 6.7.2.1/16:

как частный случай, последний элемент структуры с более чем одним именем члена может иметь неполный тип массива; это называется членом гибкой матрицы . В большинстве ситуаций гибкий элемент массива игнорируется. В частности, размер структуры выглядит так, как если бы гибкий элемент массива был опущен, за исключением того, что он может иметь более длинную прописку, чем упущение.

Однако, если оператор . (или ->) имеет левый операнд, который является (указателем на) структуру с гибким членом массива, а правый операнд - членом, он ведет себя так, как если бы этот элемент был заменен на самый длинный массив (с тем же типом элемента), который не сделает структуру больше, чем объект, к которому обращаются; смещение массива должно оставаться равным элементу гибкого элемента массива, даже если это будет отличаться от размера массива замены. Если этот массив не будет содержать никаких элементов, он будет вести себя так, как если бы у него был один элемент, но поведение не определено, если была предпринята попытка доступа к этому элементу или для создания указателя, который прошел мимо него.

+1

Означает ли это, что я не могу получить к нему доступ? –

+0

@Alan: Нет, вы все равно можете получить доступ к 'b'. – kennytm

+0

@Alan: нет; это просто означает, что sizeof() возвращает результат, который вы наблюдаете. –

2

Это потому, что вторая структура использует массив в гибкого элемента.Объяснение результата sizeof находится в Wikipedia.

1

void * b[]; недействителен в C89, поэтому это означает, что вы используете компилятор C99.

C99 представила средство для определения «STRUCT хак»: она теперь называется «гибкий элемент массива» и до того, как выделяется память, его размер равен 0.

+0

Это было также важно отметить, потому что я пытался придерживаться C89. Благодаря! –

0

Поскольку первый не объявляя никакого пространства для указатели в «b».

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