結(jié)構(gòu)體

  • 結(jié)構(gòu)體有名定義
  • 無名定義
  • 結(jié)構(gòu)體嵌套定義
  • 結(jié)構(gòu)體內(nèi)存對(duì)齊
  • 結(jié)構(gòu)體成員初始化
  • 結(jié)構(gòu)體變量引用
  1. 結(jié)構(gòu)體的有名定義:直白點(diǎn)就是在struct 之后跟著結(jié)構(gòu)體的名稱吨些,如下:
struct str_test{
    int a;
    char b;
};
  1. 結(jié)構(gòu)體的無名定義:注意與有名定義的區(qū)別盯桦。這種方式不提倡,但是系統(tǒng)支持
struct {
    int c旋圆;
    char e;
}var1麸恍,var2灵巧;  //結(jié)構(gòu)體定義完畢直接定義變量。
  1. 結(jié)構(gòu)體的嵌套定義:
struct str_test3{
    int length;
    int wide;
    int high;
    struct str_test4{
      int id;
      struct str_test3 var;
  };
}孩等;//這種也可以艾君,但是不提倡使用。

struct str_test3{
    int length;
    int wide;
    int high;
}肄方;
struct str_test4{
    int id;
    struct str_test3 var;
}冰垄;//是最常用方式,結(jié)構(gòu)體互相獨(dú)立权她;
  1. 結(jié)構(gòu)體內(nèi)存對(duì)齊
    1)虹茶、平臺(tái)原因:不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù)隅要,否則拋出硬件異常蝴罪。
    2)、性能原因:數(shù)據(jù)結(jié)構(gòu)應(yīng)該盡可能地在自然邊界上對(duì)齊步清。原因在于要门,為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問廓啊;而對(duì)齊的內(nèi)存訪問僅需要一次訪問欢搜。

這些問題既和軟件相關(guān)又和硬件相關(guān)。

  1. 所謂軟件相關(guān)主要是指和具體的編程語(yǔ)言的編譯器的特性相關(guān)谴轮,編譯器為了優(yōu)化CPU訪問內(nèi)存的效率炒瘟,在生成結(jié)構(gòu)體成員的起始地址時(shí)遵循著某種特定的規(guī)則,這就是所謂的 結(jié)構(gòu)體成員“對(duì)齊”第步;
  2. 所謂硬件相關(guān)主要是指CPU的“字節(jié)序”問題疮装,也就是大于一個(gè)字節(jié)類型的數(shù)據(jù)如int類型、short類型等粘都,在內(nèi)存中的存放順序廓推,即單個(gè)字節(jié)與高低地址的對(duì)應(yīng)關(guān)系。

字節(jié)序分為兩類:Big-Endian和Little-Endian驯杜,有的文章上稱之為“大端”和“小端”受啥,他們是這樣定義的:
Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端鸽心;
Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端滚局,低位字節(jié)排放在內(nèi)存的高地址端。

最本質(zhì)原因是基本數(shù)據(jù)類型的長(zhǎng)度有大有小顽频,在使用的時(shí)候不可能長(zhǎng)短一樣藤肢,但CPU為了提高效率需要大批量一次訪問多個(gè)內(nèi)存區(qū),可能存在同一個(gè)數(shù)據(jù)由于沒有字節(jié)對(duì)齊而出現(xiàn)跨字節(jié)訪問糯景,這樣效率會(huì)下降嘁圈,甚至有些CPU會(huì)異常省骂,比如一個(gè)大小固定的盒子如果要放進(jìn)去不整齊的筷子,就會(huì)很麻煩要么折斷要么換盒子最住,最好就是將筷子對(duì)齊同時(shí)放入盒子钞澳。

其中筷子也有大頭和小頭之分,具體怎么放那是一個(gè)約定涨缚,只要整體系統(tǒng)都采用統(tǒng)一的大頭或小頭就行轧粟。

我們?cè)谧龊凶臃趴曜拥脑囼?yàn)的時(shí)候,很多時(shí)候是我們?nèi)斯た勺R(shí)別的脓魏,能很智能完成復(fù)雜操作兰吟,那么計(jì)算機(jī)在處理數(shù)據(jù)的過程中的字節(jié)是怎么對(duì)齊的呢?

首先我們的程序在編譯階段茂翔,編譯器會(huì)稍微做些智能化的工作混蔼,將內(nèi)存的分配過程中按照一定的規(guī)則對(duì)齊,GCC 默認(rèn)的對(duì)齊字節(jié)是 4字節(jié)珊燎, vc 默認(rèn)的對(duì)齊字節(jié)是 8字節(jié)惭嚣。

在編譯過程中有個(gè)開關(guān)可以控制對(duì)齊的字節(jié)大小: #pragma pack(n) 這個(gè)宏就是來控制編譯過程中的字節(jié)對(duì)齊用的悔政,其中的 n 就是你可定制的對(duì)齊字節(jié)大小料按,如果不設(shè)置就按默認(rèn)值處理。

我們可以編寫程序來驗(yàn)證字節(jié)對(duì)齊的神奇:

struct A
{
    char a;
    int c;
};

問 如上結(jié)構(gòu)體的大小是多少卓箫?為什么? 這是一個(gè)企業(yè)面試題垄潮,類似的面試題多不勝數(shù)烹卒。

將這個(gè)結(jié)構(gòu)體編寫程序跑起來看看就知道了,在運(yùn)行之前我們按照以前學(xué)習(xí)的基本知識(shí)計(jì)算出 結(jié)果應(yīng)該是:char =1 int =4 所以結(jié)果應(yīng)該是5
但是非常抱歉弯洗,程序的運(yùn)行結(jié)果卻是:8 旅急,到底是我們計(jì)算錯(cuò)誤還是計(jì)算機(jī)出故障了?其實(shí)我們都沒錯(cuò)牡整,計(jì)算機(jī)也沒錯(cuò) 藐吮,就是字節(jié)對(duì)齊的起作用。
編譯器在編譯代碼的過程中逃贝,根據(jù)如下原則對(duì)數(shù)據(jù)對(duì)齊

  1. 數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct或聯(lián)合union)的數(shù)據(jù)成員谣辞,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從該成員大小的整數(shù)倍開始(比如int在32位機(jī)為4字節(jié)沐扳,則要從4的整數(shù)倍地址開始存儲(chǔ))泥从。
  2. 結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲(chǔ)沪摄。(struct a里存有struct b躯嫉,b里有char纱烘,int,double等元素祈餐,那b應(yīng)該從8的整數(shù)倍開始存儲(chǔ)擂啥。)
    原則
  3. 收尾工作:結(jié)構(gòu)體的總大小,也就是sizeof的結(jié)果帆阳,必須是其內(nèi)部最大成員的整數(shù)倍哺壶,不足的要補(bǔ)齊。
  4. 結(jié)構(gòu)體中的字節(jié)對(duì)齊舱痘,如果成員的大小大于等于4字節(jié)变骡,則以4字節(jié)對(duì)齊,然后再排列下一個(gè)成員芭逝。如果兩個(gè)成員的大小加起來大于四字節(jié)塌碌,則這兩個(gè)相鄰成員仍分別按照四字節(jié)對(duì)齊。僅當(dāng)兩個(gè)相鄰成員的總大小在四字節(jié)內(nèi)的時(shí)候旬盯,才會(huì)一起按照四字節(jié)對(duì)齊台妆。
    Demo:
typedef struct {
    char a;
    int b;
    short c;
}Demo1;
Demo1 tmp;
sizeof(Demo1)=12
("%p", &tmp.a) = 0
("%p", &tmp.b) = 4
("%p", &tmp.c) = 8
Demo1 tmp.png
typedef struct {
    char a;
    short b;
    int c;
}Demo2;
Demo2 tmp;
sizeof(Demo2)=8
("%p", &tmp.a) = 0
("%p", &tmp.b) = 2
("%p", &tmp.c) = 4
Demo2 tmp.png
typedef struct {
    char a;
    char b[4];
    short c; //int c
}Demo3;
Demo3 tmp;
sizeof(Demo3)=8 // 12
("%p", &tmp.a) = 0
("%p", &tmp.b) = 1
("%p", &tmp.c) = 6
Demo3 short.png
Demo3 int.png

所以我們?cè)谑褂媒Y(jié)構(gòu)體的過程中一定要注意它的這個(gè)特性,尤其是在需要用到結(jié)構(gòu)體大小的地方胖翰,一定要考慮字節(jié)對(duì)齊產(chǎn)生的影響接剩。

1)聯(lián)合體是一個(gè)結(jié)構(gòu);
2)它的所有成員相對(duì)于基地址的偏移量都為0萨咳;
3)此結(jié)構(gòu)空間要大到足夠容納最"寬"的成員懊缺;
4)其對(duì)齊方式要適合其中所有的成員;

  1. 結(jié)構(gòu)體成員初始化
struct str_test
{
    int a;
    int b;
};
struct str_test var = {10,20};   ///結(jié)構(gòu)體定義與變量定義分離培他,變量的初始化一次性完成
struct str_test var2 = {.a=30};  ///結(jié)構(gòu)體變量的成員可以單獨(dú)指定

等價(jià)

struct str_test var2 ;
    var2.a =30;
struct str_test2
{
    int aa;
    int bb;
    struct str_test cc;
};
struct str_test2 var3 = {10,20,{30,40}};   ///嵌套結(jié)構(gòu)體初始化一次性完成 
struct str_test2 var5 = {.cc.a =10};       ///嵌套結(jié)構(gòu)體成員變量的逐層賦值
struct str_test3
{
    int a;
    int b;
}var6,var7;  ///定義結(jié)構(gòu)體的時(shí)候定義變量
struct str_test4
{
    int a;
    int b;
}var8 = {100,200};  ///定義結(jié)構(gòu)體的時(shí)候定義變量并初始化
  1. 結(jié)構(gòu)體變量的引用:
    1鹃两、變量名.成員 ;
    2舀凛、指針變量 ->成員俊扳;
struct str_test var;
   var.a =10;
   var.b =20;
struct str_test pvar = NULL;    ///結(jié)構(gòu)體指針與基本數(shù)據(jù)類型的指針一樣,必須指向一個(gè)實(shí)際的內(nèi)存地址猛遍。    
pvar = (strcut str_test *) malloc(sizeof(struct str_test));

或者 定義變量同時(shí)定義指針:
struct str_test var, *pvar; pvar = &var;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馋记,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懊烤,更是在濱河造成了極大的恐慌梯醒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奸晴,死亡現(xiàn)場(chǎng)離奇詭異冤馏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寄啼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門逮光,熙熙樓的掌柜王于貴愁眉苦臉地迎上來代箭,“玉大人,你說我怎么就攤上這事涕刚∥俗郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵杜漠,是天一觀的道長(zhǎng)极景。 經(jīng)常有香客問我,道長(zhǎng)驾茴,這世上最難降的妖魔是什么盼樟? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮锈至,結(jié)果婚禮上晨缴,老公的妹妹穿的比我還像新娘。我一直安慰自己峡捡,他們只是感情好击碗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著们拙,像睡著了一般稍途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砚婆,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天械拍,我揣著相機(jī)與錄音,去河邊找鬼装盯。 笑死殊者,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的验夯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼摔刁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挥转!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起共屈,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤绑谣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拗引,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體借宵,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年矾削,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壤玫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豁护。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖欲间,靈堂內(nèi)的尸體忽然破棺而出楚里,到底是詐尸還是另有隱情,我是刑警寧澤猎贴,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布班缎,位于F島的核電站,受9級(jí)特大地震影響她渴,放射性物質(zhì)發(fā)生泄漏达址。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一趁耗、第九天 我趴在偏房一處隱蔽的房頂上張望沉唠。 院中可真熱鬧,春花似錦对粪、人聲如沸右冻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纱扭。三九已至,卻和暖如春儡遮,著一層夾襖步出監(jiān)牢的瞬間乳蛾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工鄙币, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肃叶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓十嘿,卻偏偏與公主長(zhǎng)得像因惭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绩衷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容