2012-04-26 26 views
6

Otrzymuję nietypowe zachowanie z mojego kodu, który brzmi następującoZachowanie operatora sizeof w C

#include<stdio.h> 
struct a 
{ 
    int x; 
    char y; 
}; 
int main() 
{ 
    struct a str; 
    str.x=2; 
    str.y='s'; 
    printf("%d %d %d",sizeof(int),sizeof(char),sizeof(str)); 
    getch(); 
    return 0; 
} 

Dla tego kawałka kodu otrzymuję komunikat:

4 1 8 

Jako mojego wiedza struktura zawiera zmienną całkowitą o rozmiarze 4 i zmienną char o rozmiarze 1, dlatego rozmiar struktury a powinien wynosić 5. Ale jak to się dzieje, że rozmiar struktury to 8. Używam wizualnego kompilatora C++. Dlaczego to zachowanie?

+2

W argumentach 'printf()' powinieneś rzucić wartości 'sizeof' na' (int) '... lub' (unsigned long) 'i użyć' "% lu" '... lub, jeśli mieć C99, użyj '"% zu "'. – pmg

+2

@pmg: Dokładnie. Ponieważ 'sizeof()' zwraca wartość typu 'size_t'. –

Odpowiedz

12

To się nazywa Structure Padding

Mając struktur danych, które rozpoczynają się w dniu 4 wyrównania bajt słowa (na procesorach z 4 bajtowych autobusów i przetwórców) jest znacznie bardziej wydajne przy przenoszeniu danych wokół pamięci, a między RAM i CPU.

Generalnie można wyłączyć to za pomocą opcji kompilatora i/lub pragmy, specyfika tego będzie zależeć od konkretnego kompilatora.

Mam nadzieję, że to pomoże.

+1

_Ogólnie możesz to wyłączyć off_, ale polecam nigdy tego nie robić, nawet jeśli potrzebujesz sparsować jakiś pakiet binarny i masz pomysł na stworzenie podobnej struktury dla łatwego kodowania/dekodowania. Pamiętaj, że w przypadku niektórych celów (może tylko w przeszłości) niewyrównane czytanie może doprowadzić do awarii procesora! Powoduje to również, że twój kod jest w pełni nieopłacalny. – Yury

+0

@Jak: jeśli kompilator zezwala na '#pragma pack' lub podobne rzeczy na takich platformach, zwykle generuje kod w celu obejścia wyrównanego problemu odczytu (zwykle' memcpy' do oddzielnej, wyrównanej lokalizacji), w przeciwnym razie takie struktury byłyby niezdatne do użytku . –

8

Kompilator wstawia dopełnienie w celu optymalizacji i aligmentu. Tutaj kompilator wstawia 3 bajty-bajty pomiędzy (lub po) twoimi członkami.

Możesz obsłużyć wyrównanie za pomocą dyrektywy #pragma.

+1

być może (1) 3 bajty i (2) po – Vlad

+0

Tak, to 3 bajty w tym przypadku, ale myślę, że jest między, prawda? – md5

+0

cóż, zależy to od endianiczności docelowej maszyny :) albo iiiidddc lub iiiicddd. – Vlad

0

Głównie po to, aby zilustrować, jak to podszycie działa, zmieniłem trochę Twój program.

#include<stdio.h> 
struct a 
{ 
    int x; 
    char y; 
    int z; 
}; 
int main() 
{ 
    struct a str; 
    str.x=2; 
    str.y='s'; 
    str.z = 13; 

    printf ("sizeof(int) = %lu\n", sizeof(int)); 
    printf ("sizeof(char) = %lu\n", sizeof(char)); 
    printf ("sizeof(str) = %lu\n", sizeof(str)); 

    printf ("address of str.x = %p\n", &str.x); 
    printf ("address of str.y = %p\n", &str.y); 
    printf ("address of str.z = %p\n", &str.z); 

    return 0; 
} 

Zauważ, że dodałem trzeci element do struktury. Po uruchomieniu tego programu otrzymuję:

[email protected]:~/so$ ./padding 
sizeof(int) = 4 
sizeof(char) = 1 
sizeof(str) = 12 
address of str.x = 0x7fffc962e070 
address of str.y = 0x7fffc962e074 
address of str.z = 0x7fffc962e078 
[email protected]:~/so$ 

Część tego, która ilustruje wypełnienie, jest podświetlona poniżej.

address of str.y = 0x7fffc962e074 
address of str.z = 0x7fffc962e078 

Gdy y jest tylko jednym znakiem, należy pamiętać, że z jest pełne 4 bajty.