2010-11-29 23 views

回答

16

實現沒有標準這樣做的方式。該標準規定填充可以根據實現的意願進行。來自C99 6.7.2.1 Structure and union specifiers,第12段:

結構體或聯合體對象的每個非位字段成員都以適合其類型的實現定義的方式對齊。

說了這麼多,你可以嘗試幾件事情。


您第一次四折,用#pragma,試圖說服編譯器不收拾。無論如何,這不是便攜式的。也沒有任何其他特定於實現的方法,但是您應該檢查它們,因爲如果您確實需要此功能,可能需要執行此操作。


二是從最大到最小,以訂購您的領域,如所有long long類型其次long的,那麼所有的intshort最後char類型。這通常會起作用,因爲它通常是具有更嚴格對齊要求的較大類型。再次,不便攜式。


第三,你可以定義你的類型,char陣列和投的地址,以確保沒有填充。但請記住,如果變量未正確對齊,某些體系結構將放慢速度,而其他體系結構將會失敗(例如,引發BUS錯誤並終止您的過程)。

最後一個有一些進一步的解釋。假設你有以下順序的字段的結構:

char C; // one byte 
int I; // two bytes 
long L; // four bytes 

隨着填充,你可以用下面的字節結束:

CxxxIIxxLLLL 

其中x是填充。

但是,如果你定義了你的結構爲:

typedef struct { char c[7]; } myType; 
myType n; 

你:

CCCCCCC 

然後,您可以這樣做:

int *pInt = &(n.c[1]); 
int *pLng = &(n.c[3]); 
int myInt = *pInt; 
int myLong = *pLng; 

給你:

CIILLLL 

不幸的是,不能攜帶。


所有這些「解決方案」都依賴於您熟悉編譯器和底層數據類型。

3

除了像編譯指示包這樣的編譯選項以外,不能在C標準中填充填充。

你總是可以嘗試通過在結構最後宣佈最小的類型,在減少填充:

struct _foo { 
    int a; /* No padding between a & b */ 
    short b; 
} foo; 

struct _bar { 
    short b; /* 2 bytes of padding between a & b */ 
    int a; 
} bar; 

對於具有4個字節邊界

1

在某些體系結構上,如果系統要求處理未對齊的數據,CPU本身會反對。要解決這個問題,編譯器可以生成多個對齊的讀或寫指令,移位和分割或合併各個位。您可以合理地預期它比對齊的數據處理慢5到10倍。但是,該標準並不要求編譯器做好準備......考慮到性能成本,它只是沒有足夠的需求。支持顯式控制填充的編譯器提供了它們自己的編譯指示,這是因爲編譯指示保留用於非標準功能。

如果您必須使用未打底數據,請考慮編寫您自己的訪問例程。您可能想要嘗試使用較少對齊的類型(例如,使用char/int8_t),但仍有可能例如結構的大小將被四捨五入爲4的倍數,這會嚴重阻礙打包結構,在這種情況下,您需要實現對整個內存區域的訪問。

0

要麼讓編譯器進行填充,要麼告訴它不要使用#pragma,要麼就像使用char數組一樣使用一些字節,並且自己構建所有數據(移位和添加字節)。這實際上效率很低,但你會精確控制字節的佈局。我曾經這樣做過,有時手動準備網絡數據包,但在大多數情況下,這是一個壞主意,即使它是標準的。

0

如果您確實需要不帶填充的結構:使用僅由8位字節組成的結構或類來定義short,int,long等的替換數據類型。然後使用替換數據類型編寫更高級別的結構。

C++的操作符重載非常方便,但是您可以在C中使用結構而不是類實現相同的效果。下面的轉換和賦值實現假定CPU可以處理未對齊的32位整數,但其他實現可以容納更嚴格的CPU。

下面是示例代碼:

#include <stdint.h> 
#include <stdio.h> 

class packable_int { public: 

    int8_t b[4]; 

    operator int32_t() const  { return *(int32_t*) b; } 
    void operator = (int32_t n) { *(int32_t*) b = n; } 

}; 

struct SA { 
    int8_t c; 
    int32_t n; 
} sa; 

struct SB { 
    int8_t  c; 
    packable_int n; 
} sb; 

int main() { 
    printf ("sizeof sa %d\n", sizeof sa); // sizeof sa 8    
    printf ("sizeof sb %d\n", sizeof sb); // sizeof sb 5    
    return 0; 
} 
0

我們所用的C程序使用以下方法中的任何一個禁用結構填充。

- >使用__attribute__((packed))定義結構。例如。

struct node { 
    char x; 
    short y; 
    int z; 
} __attribute__((packed)); 

- >在編譯c代碼時使用-fpack-struct標誌。例如。

$ gcc -fpack-struct -o tmp tmp.c

希望這會有所幫助。 謝謝。

相關問題