3.20.2011

GNU C的__PACK__ __attribute__ ((packed))

最近在看Source Code的時後,忽然注意到一個關鍵字─__PACK__
unsigned char strUserName[MAX_LEN + 1] __PACK__;
unsigned int unDHCPMode __PACK__;
之前都沒有特別留意,反正別人怎麼宣告,自己也跟著寫就對了;直到最近才想到,於是就上網Google一下,把自己所理解的,記錄下來。

那__PACK__到底是什麼??假如在你的開發環境中搜尋這個字串,相信應該不難找到會在某個檔案裡出現這一行:
#define __PACK__ __attribute__ ((packed))
當我們去宣告一個變數的時後,會用掉多少記憶體,通常會去用sizeof()來去計算;但Compiler為了效能考量,會自動地幫我們的程式碼做最佳化的運算,換句話說─就是會偷偷幫我們多準備一些記憶體空間

請看以下的簡單範例:
// OS: Linux Red Hat 9
// File Name: Main.c
#include <stdio.h>

int main(void)
{
    int nTemp = 0;
    short int snTemp = 0;
    long lnTemp = 0L;
    float fTemp = 0;
    char cTemp = '\0';
    long long lnlnTemp = 0LL;
    double dTemp = 0;

    printf("1. sizeof(int) = %d, sizeof(nTemp) = %d \n", sizeof(int), sizeof(nTemp));
    printf("2. sizeof(short int) = %d, sizeof(snTemp) = %d \n", sizeof(short int), sizeof(snTemp));
    printf("3. sizeof(long) = %d, sizeof(lnTemp) = %d \n", sizeof(long), sizeof(lnTemp));
    printf("4. sizeof(float) = %d, sizeof(fTemp) = %d \n", sizeof(float), sizeof(fTemp));
    printf("5. sizeof(char) = %d, sizeof(cTemp) = %d \n", sizeof(char), sizeof(cTemp));
    printf("6. sizeof(long long) = %d, sizeof(lnlnTemp) = %d \n", sizeof(long long), sizeof(lnlnTemp));
    printf("7. sizeof(double) = %d, sizeof(dTemp) = %d \n", sizeof(double), sizeof(dTemp));

    return 0;
}
gcc ./Main.c -o Main; ./Main

會得到以下的結果:

1. sizeof(int) = 4, sizeof(nTemp) = 4
2. sizeof(short int) = 2, sizeof(snTemp) = 2
3. sizeof(long) = 4, sizeof(lnTemp) = 4
4. sizeof(float) = 4, sizeof(fTemp) = 4
5. sizeof(char) = 1, sizeof(cTemp) = 1
6. sizeof(long long) = 8, sizeof(lnlnTemp) = 8
7. sizeof(double) = 8, sizeof(dTemp) = 8

OK!!那我們現在把程式碼改成用結構 (struct)的方式來呈現:
#include <stdio.h>

struct DATA_T
{
    int nTemp;
    short int snTemp;
    long lnTemp;
    float fTemp;
    char cTemp;
    long long lnlnTemp;
    double dTemp;
};

int main(void)
{
    struct DATA_T stTemp;

    printf("8. sizeof(struct DATA_T) = %d, sizeof(stTemp) = %d \n", sizeof(struct DATA_T), sizeof(stTemp));

    return 0;
}
得到的結果是:

8. sizeof(struct DATA_T) = 36, sizeof(stTemp) = 36

問題來了,DATA_T這個結構,也是由7種不一樣的資料型態所組成。所以,理論上這個DATA_T所佔用的記憶體空間應為:

4 + 2 + 4 + 4 + 1 + 8 + 8 = 31

應該要31 Bytes才對,為什麼會變成36呢??這就是電腦幫我們做最佳化的處理。把記憶體的空間最佳化為2的倍數。

承以上程式碼,我們再多加一行:
#include <stdio.h>
#define __PACK__ __attribute__((packed))

struct DATA_T
{
    int nTemp;
    short int snTemp;
    long lnTemp;
    float fTemp;
    char cTemp;
    long long lnlnTemp;
    double dTemp;
} __PACK__;

int main(void) {

    struct DATA_T stTemp;

    printf("9. sizeof(struct DATA_T) = %d, sizeof(stTemp) = %d \n", sizeof(struct DATA_T), sizeof(stTemp));

    return 0;
}
這次所得到的結果:

9. sizeof(struct DATA_T) = 31, sizeof(stTemp) = 31

就如同我們所期待地一樣了!!其中第二個程式碼的範例,在一般的PC上基本上是沒有什麼問題的;若是在記憶體寸土寸金的嵌入式系統上,可就不行了。

若想要瞭解更多__attribute__((packed))的用法,請參閱 (其實是我懶的寫....XD):
http://huenlil.pixnet.net/blog/post/26078382

沒有留言:

張貼留言