__attribute__ ((packed)) 的作用 用法

來源:互聯網
上載者:User

詳細英文解釋 http://www.unixwiz.net/techtips/gnu-c-attributes.html


為了編寫可以在不同平台之間可移植的資料項目的資料結構,除了規定特定的位元組序以外,還應該始終強制資料項目的自然對齊。 
自然對齊(Natural Alignment)是指在資料項目大小的整數倍(例如,8位元組資料項目存入8的整數倍的地址)的地址處儲存資料項目。 
強制自然對齊可以防止編譯器移動資料結構的欄位,你應該使用填充符(filer)欄位來避免在資料結構中留下空洞。

編譯器本身可能會往結構體中插入填充資料,以確保每個欄位的對齊可以在目標處理器上取得好的效能。 
如果正在定義一個和裝置要求的結構體相匹配的結構體,這種自動填滿會破壞你的意圖。解決的辦法是告訴編譯器結構體必須是“填滿的”,不能添加填充符。 
就是在結構體聲明的地方加上__attribute__((packed)),例如: 

struct {     u16 id;     u64 lun;     u16 reserved1;     u32 reserved2; } __attribute__ ((packed)) scsi;

如果沒有__attribute__((packed)),lun欄位前面會被插入兩個填充位元組,按4位元組對齊。



1. __attribute__ ((packed)) 的作用就是告訴編譯器取消結構在編譯過程中的最佳化對齊,按照實際佔用位元組數進行對齊,是GCC特有的文法。這個功能是跟作業系統沒關係,跟編譯器有關,gcc編譯器不是緊湊模式的,我在windows下,用vc的編譯器也不是緊湊的,用tc的編譯器就是緊湊的。例如:

在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(緊湊模式)

在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非緊湊模式)

在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5

2. __attribute__關鍵字主要是用來在函數或資料聲明中設定其屬性。給函數賦給屬性的主要目的在於讓編譯器進行最佳化。函式宣告中的__attribute__((noreturn)),就是告訴編譯器這個函數不會返回給調用者,以便編譯器在最佳化時去掉不必要的函數傳回碼。

GNU C的一大特色就是__attribute__機制。__attribute__可以設定函數屬性(Function Attribute)、變數屬性(Variable Attribute)和類型屬性(Type Attribute)。

__attribute__書寫特徵是:__attribute__前後都有兩個底線,並且後面會緊跟一對括弧,括弧裡面是相應的__attribute__參數。

__attribute__文法格式為:

__attribute__ ((attribute-list))

其位置約束:放於聲明的尾部“;”之前。

函數屬性(Function Attribute):函數屬性可以協助開發人員把一些特性添加到函式宣告中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程式做到相容之功效。

GNU CC需要使用 –Wall編譯器來擊活該功能,這是控制警告資訊的一個很好的方式。

packed屬性:使用該屬性可以使得變數或者結構體成員使用最小的對齊,即對變數是一位元組對齊,對域(field)是位對齊。

如果你看過GPSR協議在TinyOS中的實現,你一定會注意到下面的語句:
typedef struct {
    double x;
    double y;
} __attribute__((packed)) position_t;

開始我們還可以理解,不久是定義一個結構體嘛。不過看到後面的語句,你可能就會一頭霧水了,’ __attribute__((packed))’是什麼東西。有什麼作用。一連串的疑問馬上就會從你腦袋裡冒出來。雖然這個對理解整個程式沒有什麼影響,但我不想讓這些疑問一直呆在我的腦子裡,負擔太重。省得以後念念不忘,而且也許有一天可以用的上呢。搞清楚這個問題吧。

GNU C的一大特色(卻不被初學者所知)就是__attribute__機制。__attribute__可以設定函數屬性(Function Attribute)、變數屬性(Variable Attribute)和類型屬性(Type Attribute)。
__attribute__文法格式為:
__attribute__ ((attribute-list))

其位置約束為:放於聲明的尾部“;”之前。

packed是類型屬性(Type Attribute)的一個參數,使用packed可以減小對象佔用的空間。需要注意的是,attribute屬性的效力與你的連接器也有關,如果你的連接器最大隻支援16位元組對齊,那麼你此時定義32位元組對齊也是無濟於事的。

使用該屬性對struct或者union類型進行定義,設定其類型的每一個變數的記憶體約束。當用在enum類型定義時,暗示了應該使用最小完整的類型(it indicates that the smallest integral type should be used)。

下面的例子中,my-packed-struct類型的變數數組中的值會緊湊在一起,但內部的成員變數s不會被“pack”,如果希望內部的成員變數也被packed的話,my-unpacked-struct也需要使用packed進行相應的約束。
struct my_unpacked_struct
{
     char c;
     int i;
};
         
struct my_packed_struct
{
     char c;
     int i;
     struct my_unpacked_struct s;
}__attribute__ ((__packed__));

 

 

在每個系統上看下這個結構體的長度吧。
    記憶體對齊,往往是由編譯器來做的,如果你使用的是gcc,可以在定義變數時,添加__attribute__,來決定是否使用記憶體對齊,或是記憶體對齊到幾個位元組,以上面的結構體為例:
 1)到4位元組,同樣可指定對齊到8位元組。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 

2)不對齊,結構體的長度,就是各個變數長度的和
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));

 

 

 

 

  跨平台時基於資料結構的網路通訊     網路通訊通常分為基於資料結構的和基於流的。HTTP協議就是後者的一個例子。
    有時為了提高程式的處理速度和資料處理的方便,會使用基於資料結構的通訊(不需要對流進行解析)。但是,當需要在多平台間進行通訊時,基於資料結構的通訊,往往要十分注意以下幾個方面:
[1] 位元組序
[2] 變數長度
[3] 記憶體對齊
    在常見的系統架構中(Linux X86,Windows),非單位元組長度的變數類型,都是低位元組在前,而在某些特定系統中,如Soalris Sparc平台,高位元組在前。如果在發送資料前不進行處理,那麼由Linux X86發向Soalris Sparc平台的資料值,勢必會有極大的偏差,進而程式運行過程中無法出現預計的正常結果,更嚴重時,會導致段錯誤。
    對於此種情況,我們往往使用同一的位元組序。在系統中,有ntohXXX(), htonXXX()等函數,負責將資料在網路位元組序和本地位元組序之間轉換。雖然每種系統的本地位元組序不同,但是對於所有系統來說,網路位元組序是固定的-----高位元組在前。所以,可以以網路位元組序為通訊的標準,發送前,資料都轉換為網路位元組序。
    轉換的過程,也建議使用ntohXXX(), htonXXX()等標準函數,這樣代碼可以輕鬆地在各平台間進行移植(像通訊這種很少依賴系統API的代碼,做成通用版本是不錯的選擇)。

    變數的長度,在不同的系統之間會有差別,如同是Linux2.6.18的平台,在64位系統中,指標的長度為8個位元組,而在32位系統中,指標又是4個位元組的長度---此處只是舉個例子,很少有人會將指標作為資料發送出去。下面是我整理的在64位Linux系統和32位Linux系統中,幾種常見C語言變數的長度:
                short    int    long    long long    ptr    time_t
32位           2         4       4             8               4        4
64位           2         4       8             8               8        8
    在定義通訊用的結構體時,應該考慮使用定常的資料類型,如uint32_t,4位元組的固定長度,並且這屬於標準C庫(C99),在各系統中都可使用。

    記憶體對齊的問題,也與系統是64位還是32位有關。如果你手頭有32位和64位系統,不妨寫個簡單的程式測試一下,你就會看到同一個結構體,即便使用了定常的資料類型,在不同系統中的大小是不同的。對齊往往是以4位元組或8位元組為準的,只要你寫的測試程式,變數所佔空間沒有對齊到4或8的倍數即可,舉個簡單的測試用的結構體的例子吧:
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
};
    在每個系統上看下這個結構體的長度吧。
    記憶體對齊,往往是由編譯器來做的,如果你使用的是gcc,可以在定義變數時,添加__attribute__,來決定是否使用記憶體對齊,或是記憶體對齊到幾個位元組,以上面的結構體為例:
 1)到4位元組,同樣可指定對齊到8位元組。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 

2)不對齊,結構體的長度,就是各個變數長度的和
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.