原文地址:::http://blog.csdn.net/wbczyh/article/details/2100878前兩天在編寫一段代碼時突然對結構體在函數中的用法有些模糊了,經過複習,基本弄清了這些知識,特總結如下:一、結構體與函數參數 結構體作函數參數可分為傳值與傳指標。 1.傳值時結構體參數會被拷貝一份,在函數體內修改結構體參數成員的值實際上是修改調用參數的一個臨時拷貝的成員的值,這不會影響到調用參數。在這種情況下,由於涉及到結構體參數的拷貝,程式空間及時間效率都會受到影響,所以這種方法基本不用。 例如: typedef struct tagSTUDENT{
char name[20];
int age;}STUDENT; void fun(STUDENT stu){ printf(“stu.name=%s,stu.age=%d/n”,stu.name,stu.age);} 2.傳指標時直接將結構體的首地址傳遞給函數體,在函數體中通過指標引用結構體成員,可以對結構體參數成員的值造成實際影響。這種用法效率高,經常採用。 例如: typedef struct tagSTUDENT{char name[20];int age;}STUDENT; void fun(STUDENT* pStu){printf(“pStu->name=%s,pStu->age=%d/n”,pStu->name,pStu->age);} 二、結構體與函數傳回值 對於某些版本的C語言編譯器,傳回值僅能為基礎資料型別 (Elementary Data Type)如int、char以及指標,因此結構體作為一種組合資料類型,不能以值的方式返回,而在有些版本的C編譯器中又可以直接返回結構體變數 ,在C++中也是可以直接返回結構體變數的。 直接返回結構體變數樣本如下; typedef struct tagSTUDENT{char name[20];int age;}STUDENT; STUDENT fun();int _tmain(int argc, _TCHAR* argv[]){ STUDENT p=fun(); printf("p.name=%s",p.name); return 0;} STUDENT fun(){ STUDENT stu; stu.age=18; strcpy(stu.name,"xiaoming"); return stu;} 以指標方式返回結構體樣本如下: typedef struct tagSTUDENT{char name[20];int age;}STUDENT; STUDENT* fun(){ STUDENT* p=malloc(sizeof(STUDENT)); p->age=18; strcpy(p->name,"xiaoming"); return p;} 以上就是我對結構體在C函數中的用法做的一小結,有不妥之處請不吝賜教,大家共同進步啊! 關於結構體,看核心又遇到了,關於賦值中存在·的奇怪用法,在網上沒有找到答案,卻把以前一直弄的比較模糊的對齊問題給翻出來了。如下為轉寄內容:
有人給對齊原則做過總結,具體在哪裡看到現在已記不起來,這裡引用一下前人的經驗(在沒有#pragma pack宏的情況下):
原則1、資料成員對齊規則:結構(struct或聯合union)的資料成員,第一個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍地址開始儲存)。
原則2、結構體作為成員:如果一個結構裡有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始儲存。(struct a裡存有struct b,b裡有char,int,double等元素,那b應該從8的整數倍開始儲存。)
原則3、收尾工作:結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數倍,不足的要補齊。
這三個原則具體怎樣理解呢?我們看下面幾個例子,通過執行個體來加深理解。
例1:struct{
short a1;
short a2;
short a3;
}A;
struct{
long a1;
short a2;
}B;
sizeof(A) = 6; 這個很好理解,三個short都為2。
sizeof(B) = 8; 這個比是不是比預想的大2個位元組?long為4,short為2,整個為8,因為原則3。
例2:struct A{
int a;
char b;
short c;
};
struct B{
char b;
int a;
short c;
};
sizeof(A) = 8; int為4,char為1,short為2,這裡用到了原則1和原則3。
sizeof(B) = 12; 是否超出預想範圍?char為1,int為4,short為2,怎麼會是12?還是原則1和原則3。
深究一下,為什麼是這樣,我們可以看看記憶體裡的布局情況。
a b c
A的記憶體布局:1111, 1*, 11
b a c
B的記憶體布局:1***, 1111, 11**
其中星號*表示填充的位元組。A中,b後面為何要補充一個位元組?因為c為short,其起始位置要為2的倍數,就是原則1。c的後面沒有補充,因為b和c正好佔用4個位元組,整個A佔用空間為4的倍數,也就是最大成員int類型的倍數,所以不用補充。
B中,b是char為1,b後面補充了3個位元組,因為a是int為4,根據原則1,起始位置要為4的倍數,所以b後面要補充3個位元組。c後面補充兩個位元組,根據原則3,整個B佔用空間要為4的倍數,c後面不補充,整個B的空間為10,不符,所以要補充2個位元組。
再看一個結構中含有結構成員的例子:
例3:struct A{
int a;
double b;
float c;
};
struct B{
char e[2];
int f;
double g;
short h;
struct A i;
};
sizeof(A) = 24; 這個比較好理解,int為4,double為8,float為4,總長為8的倍數,補齊,所以整個A為24。
sizeof(B) = 48; 看看B的記憶體布局。
e f g h i
B的記憶體布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * *
i其實就是A的記憶體布局。i的起始位置要為24的倍數,所以h後面要補齊。把B的記憶體布局弄清楚,有關結構體的對齊基本就算掌握了。
以上講的都是沒有#pragma pack宏的情況,如果有#pragma pack宏,對齊按照宏的定義來。比如上面的結構體前加#pragma pack(1),記憶體的布局就會完全改變。sizeof(A) = 16; sizeof(B) = 32;
有了#pragma pack(1),記憶體不會再遵循原則1和原則3了,按1位元組對齊。沒錯,這不是理想中的沒有記憶體對齊的世界嗎。
a b c
A的記憶體布局:1111, 11111111, 1111
e f g h i
B的記憶體布局:11, 1111, 11111111, 11 , 1111, 11111111, 1111
那#pragma pack(2)的結果又是多少呢?#pragma pack(4)呢?留給大家自己思考吧,相信沒有問題。
還有一種常見的情況,結構體中含位域欄位。位域成員不能單獨被取sizeof值。C99規定int、unsigned int和bool可以作為位域類型,但編譯器幾乎都對此作了擴充,允許其它類型類型的存在。
使用位域的主要目的是壓縮儲存,其大致規則為:
1) 如果相鄰位域欄位的類型相同,且其位寬之和小於類型的sizeof大小,則後面的欄位將緊鄰前一個欄位儲存,直到不能容納為止;
2) 如果相鄰位域欄位的類型相同,但其位寬之和大於類型的sizeof大小,則後面的欄位將從新的儲存單元開始,其位移量為其類型大小的整數倍;
3) 如果相鄰的位域欄位的類型不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式,Dev-C++採取壓縮方式;
4) 如果位域欄位之間穿插著非位域欄位,則不進行壓縮;
5) 整個結構體的總大小為最寬基本類型成員大小的整數倍。
還是讓我們來看看例子。
例4:struct A{
char f1 : 3;
char f2 : 4;
char f3 : 5;
};
a b c
A的記憶體布局:111, 1111 *, 11111 * * *
位域類型為char,第1個位元組僅能容納下f1和f2,所以f2被壓縮到第1個位元組中,而f3隻能從下一個位元組開始。因此sizeof(A)的結果為2。
例5:struct B{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};
由於相鄰位域類型不同,在VC6中其sizeof為6,在Dev-C++中為2。
例6:struct C{
char f1 : 3;
char f2;
char f3 : 5;
};
非位域欄位穿插在其中,不會產生壓縮,在VC6和Dev-C++中得到的大小均為3。
考慮一個問題,為什麼要設計記憶體對齊的處理方式呢?如果體繫結構是不對齊的,成員將會一個挨一個儲存,顯然對齊更浪費了空間。那麼為什麼要使用對齊呢?體繫結構的對齊和不對齊,是在時間和空間上的一個權衡。對齊節省了時間。假設一個體繫結構的字長為w,那麼它同時就假設了在這種體繫結構上對寬度為w的資料的處理最頻繁也是最重要的。它的設計也是從優先提高對w位元據操作的效率來考慮的。有興趣的可以google一下,人家就可以跟你解釋的,一大堆的道理。
最後順便提一點,在設計結構體的時候,一般會尊照一個習慣,就是把佔用空間小的類型排在前面,佔用空間大的類型排在後面,這樣可以相對節約一些對齊空間