1. 程式人生 > >C和指針之結構體和聯合體

C和指針之結構體和聯合體

第一個 test col 聚合 要求 拷貝 破壞 存儲位置 字節

1、結構體基礎知識   聚合數據類型(aggregate data type)能夠同時存儲超過一個的單獨數據。C語言提供了兩種類型的聚合數據結構,數組和結構體。   數組是相同類型的數據元素的集合,它的每個元素都是通過下標引用或者指針間接訪問來選擇的;結構也是一些值的集合,這些值稱為它的成員(member),結構體的每個成員可以是不同類型的數據,要訪問結構體中的數據,是通過成員名來訪問的。   結構變量屬於標量類型,所以你可以像對待其他標量類型一樣執行相同類型的操作。結構體可以作為傳遞給函數的參數,也可以作為返回值從函數返回,相同類型的結構體變量之間可以相互賦值。你也可以申明指向結構體的指針,取一個結構體變量的地址,還可以聲明結構體數組。 1)聲明結構體
typedef struct
tagTEST_DATA { int a; int *p; char b; char c[]; }ST_TEST_DATA;
2)結構體成員的訪問   點操作符(.):對結構體成員進行直接訪問。點操作符接受兩個操作數,左操作數就是結構變量的名字,右操作數就是需要訪問的成員的名字。   箭頭操作符(->):對結構體成員進行間接訪問。和點操作符一樣,箭頭操作符接受兩個操作數,但是左操作數必須是一個指向結構的指針,右操作數也是需要訪問的成員的名字。 2、結構體的存儲分配
typedef struct tagST_TEST
{
    char a;
    int b;
    char c
}ST_TEST;
結構體內存分配遵循邊界對齊原則。 1)普通數據成員對齊原則:第一個數據成員放在offset為0的地方,以後每個數據成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機為4字節,則要從4的整數倍地址開始存儲)。 2)結構體成員對齊原則:如果一個結構裏有某些結構體成員,則該結構體成員要從其內部最大元素大小的整數倍地址開始存儲。 3)結構體大小對齊原則:結構體大小也就是sizeof的結果,必須是其內部成員中最大的對齊參數的整數倍,不足的要補齊。 以如上結構體ST_TEST為例:   成員a、c為char型,各占一個字節,b為int型,占4個字節,如果你認為結構體ST_TEST占了6個字節的空間,那麽你就大錯特錯了。因為沒有遵循結構體邊界對齊原則。下面我們來分析一下。按照邊界對齊原則,結構體成員要從內部最大元素大小的整數倍地址開始存儲,例子結構體中的成員最大的是int型的b,占4個字節,所以,char a和char c都要占4個字節,第一個字節為數據a、c,後三個為空。所以ST_TEST結構體共占了12個字節的空間。 如果將結構體改為如下形式:
typedef struct
tagST_TEST1 { int b; char a; char c; }ST_TEST1;
  此時,int型的b占4個字節,char a,char c各占一個,但是在其後要補兩個空字節(此時的對齊原則按照int型的4字節計算,但是,兩個char連在一起,可以算一個整體,共占4個字節),此時結構體ST_TEST1總共占了8個字節的空間,比ST_TEST少了4個字節。   以後在定義結構體時要考慮邊界對齊原則,可以通過改變成員的先後順序來達到節省存儲空間的目的。但是這樣做有時有會破壞程序的可維護性和可讀性,所以多做編程練習,在存儲空間和可讀性中找到平衡,提高自己的編程水平。   sizeof操作符能夠得出一個結構體的整體長度,包括因邊界對齊原則而跳過的那些字節。   offsetof宏則能夠得出某個成員的實際位置,需要考慮邊界對齊因素。offsetof(type, member)(定義於stddef.h)type是結構體的類型,member是需要的成員名,返回值為size_t類型的指定成員開始存儲的位置距離結構體開始存儲的位置的偏移的字節數。如offsetof(struct ST_TEST, b),返回值為4。 3、作為函數參數的結構   結構體變量是一個標量,它可以用於其他標量可以使用的任何場所。因此把結構體作為一個參數傳遞給函數是合法的。   將一個結構體直接作為參數傳遞給函數是一種及其低效的做法,因為C語言的參數傳值調用方式要求把參數的一份拷貝傳遞給函數,要想把結構體直接傳遞給函數,就需要把整個結構體都復制到堆棧中,這顯然非常浪費存儲空間。所以傳遞一個指向結構的指針給函數,效率要高很多。在函數中要訪問結構成員只需要用間接訪問的方式就可以了。 4、聯合體(共用體)   在結構體中,結構的各成員順序排列存儲,每個成員都有自己獨立的存儲位置。聯合(union)變量的所有成員共享同片存儲區/內存。因此聯合變量每個時刻裏只能保存它的某一個成員的值。 聯合變量也可以在定義時直接初始化,但這個初始化只能對第一個成員進行。 聯合體的主要特征:   union中可以定義多個成員,union的大小由最大的成員的大小決定;   union成員共享同一塊大小的內存,一次只能使用其中的一個成員;   對union某一個成員賦值,會覆蓋其他成員的值(但前提是成員所占字節數相同,當成員所占字節數不同時只會覆蓋相應字節上的值,比如對char成員賦值就不會把整個int成員覆蓋掉,因為char只占一個字節,而int占四個字節);   union量的存放順序是所有成員都從低地址開始存放的。

C和指針之結構體和聯合體