2012-06-21 18 views
6

Chcę, aby rozmiar struktury C był wielokrotnością 16 bajtów (16B/32B/48B/..). Nie ma znaczenia, jaki rozmiar osiąga, to musi być wielokrotnością 16B. Jak mogę wymusić kompilator, aby to zrobić? Dzięki.C wyrównanie rozmiaru struktury

+4

Co to jest kompilator? – Joe

+1

Twój tytuł używa wyrównania słowa, jednak treść twojego pytania mówi o wielkości struktury. Co właściwie chcesz osiągnąć? I jestem też ciekawy, dlaczego. –

+0

A tutaj jest istniejący artykuł, który zapewnia rozwiązanie za pomocą unii do pad do określonego rozmiaru. Jednak to rozwiązanie wymaga znajomości rozmiaru struct [Size of Struct] (http://stackoverflow.com/questions/8705665/force-specific-struct-size-in-c), ale to, co musisz zrobić, to użyć obliczenie rozmiaru dla tablicy char, takie jak (sizeof (struct it)/16 + 1) * 16 zamiast stałej liczbowej. –

Odpowiedz

5

Wielkość struktury C zależy od członków struktury, ich typów i ich liczby. Naprawdę nie ma standardowego sposobu zmuszenia kompilatora do tego, aby struktura była wielokrotnością pewnego rozmiaru. Niektóre kompilatory dostarczają pragmy, która pozwoli ci ustawić granicę wyrównania, ale to naprawdę jest coś innego. I mogą istnieć takie, które będą miały takie ustawienie lub zapewnią taką pragmę.

Jednakże, jeśli nalegasz na tę jedną metodę, to przydzielenie pamięci struktury i wymuszenie przydzielenia pamięci na zaokrąglenie do 16 bajtów.

Więc jeśli masz taką strukturę.

struct _simpleStruct { 
    int iValueA; 
    int iValueB; 
}; 

Następnie można zrobić coś takiego.

{ 
    struct _simpleStruct *pStruct = 0; 
    pStruct = malloc ((sizeof(*pStruct)/16 + 1)*16); 
    // use the pStruct for whatever 
    free(pStruct); 
} 

To, co można zrobić, to przesunąć rozmiar do 16 bajtów o ile dotyczy. Jednak to, co robi alokator pamięci, może, ale nie musi, dać blok, który jest w rzeczywistości tym rozmiarem. Blok pamięci może być w rzeczywistości większy niż twoja prośba.

Jeśli masz zamiar zrobić coś specjalnego z tym, na przykład powiedzmy, że zamierzasz napisać tę strukturę do pliku i chcesz poznać rozmiar bloku, to musiałbyś zrobić to samo obliczenie malloc() zamiast używania operatora sizeof() do obliczenia rozmiaru struktury.

Następną rzeczą byłoby napisanie własnego operatora sizeof() przy użyciu makra takiego jak.

#define SIZEOF16(x) ((sizeof(x)/16 + 1) * 16) 

O ile wiem, nie ma niezawodny sposób na ciągnięcie rozmiaru przydzielonego bloku od wskaźnika. Zwykle wskaźnik będzie miał blok alokacji pamięci, który jest używany przez funkcje zarządzania pamięcią sterty, które będą zawierać różne informacje zarządzania pamięcią, takie jak przydzielony rozmiar bloku, który może być faktycznie większy niż żądana ilość pamięci. Jednak format tego bloku i jego lokalizacja względem rzeczywistego adresu pamięci będą zależały od czasu działania kompilatora C.

+0

Powinieneś [nie rzucić wartości zwracanej 'malloc()', w C] (http://stackoverflow.com/a/605858/28169). – unwind

5

To zależy całkowicie od kompilatora i innych narzędzi, ponieważ wyrównanie nie jest określone tak głęboko w standardzie ISO C (określa, że ​​wyrównanie może się zdarzyć na żądanie kompilatora, ale nie zawiera szczegółowych informacji na temat jego egzekwowania).

Musisz zajrzeć do rzeczy związanych z implementacją łańcucha narzędzi kompilatora. Może dostarczyć #pragma pack (lub align lub coś innego), które można dodać do definicji struktury.

Może to również zapewnić jako rozszerzenie języka. Na przykład, gcc pozwala na dodawanie atrybutów do zdefiniowania, z których jeden steruje wyrównania:

struct mystruct { int val[7]; } __attribute__ ((aligned (16))); 
11

dla Microsoft Visual C++:

#pragma pack(push, 16) 

struct _some_struct 
{ 
    ... 
} 

#pragma pack(pop) 

dla GCC:

struct _some_struct { ... } __attribute__ ((aligned (16))); 

Przykład:

#include <stdio.h> 

struct test_t { 
    int x; 
    int y; 
} __attribute__((aligned(16))); 

int main() 
{ 
    printf("%lu\n", sizeof(struct test_t)); 
    return 0; 
} 

skompilowany z gcc -o main main.c wyświetli 16. To samo dotyczy innych kompilatorów.

+1

Dla wyrównania gcc __attribute__, czy to faktycznie zmusza rozmiar struktury do wielokrotności 16B? Czy to tylko gwarantuje, że adres początkowy struktury jest wyrównany do 16B? –

+1

Zarówno adres początkowy, jak i rozmiar struktury zostaną wyrównane do 16B. Odbywa się to w celu zapewnienia prawidłowego wyrównania elementów tablicy struktur. – Romeo

+0

To nie jest prawda. Makro __attribute (wyrównane (x))) przydziela strukturę na granicy x-bajtów i nie ma nic wspólnego z rozmiarem struktury http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc /Variable-Attributes.html –

3

Można chyba zrobić podwójne struct, owijając swoje rzeczywiste struct w drugim, który może dodać padding:

struct payload { 
    int a; /*Your actual fields. */ 
    float b; 
    char c; 
    double d; 
}; 

struct payload_padded { 
    struct payload p; 
    char padding[16 * ((sizeof (struct payload) + 15)/16)]; 
}; 

Następnie można pracować z wyściełanym struct:

struct payload_padded a; 

a.p.d = 43.3; 

Oczywiście , możesz skorzystać z faktu, że pierwszy element struktury zaczyna 0 bajtów od miejsca rozpoczęcia struktury i traktuje wskaźnik jako struct payload_padded tak, jakby był wskaźnikiem do struct payload (ponieważ jest):

float d_plus_2(const struct payload *p) 
{ 
    return p->d + 2; 
} 

/* ... */ 

struct payload_padded b; 
const double dp2 = d_plus_2((struct payload *) &b);