c語言結構體字節對齊與位域,c語言字節對齊問題詳解

本文目錄一覽:

c語言 結構體位域問題

c存在第三個字節

sizeof結構體,這個要看結構體內變量是如何定義的,結構體存放數據有個對齊原則,找到佔用最大字節的變量,然後都向它對齊,比如bool和char類型佔用一個字節,short佔兩個字節,int,float為4個字節,double為八個字節。

定義的順序不同,sizeof的結果不同。我給你舉個例子。

struct A{

    int a;

    char b;

    char c;

};

sizeof(A)應該為4+1+1,但是需要對齊,所以這個值就是 8  

圖1

這個是struct A的變量存儲

struct B{

    char a;

    int b;

    char c;

};

sizeof(B) 這個值就是12

圖2

這個是struct B的變量存儲

C語言結構體長度字節對齊問題

因為當結構體中有多個數據類型時,結構體的長度對齊是按數據類型長度最長的那個來對齊的,double類型佔8個字節,所以每個成員變量都按8個字節的長度來算,就是5*8=40,驗證程序如下:

#include stdio.h

struct chji

{

char name[9];

int number;

char sex;

double score;

float aa;

};

struct chji stu;

int main()

{

printf(“sizeof(struct chji)=%d\n”,sizeof(struct chji));

return 0;

}

運行結果:sizeof(struct chji)=40

如果要按單個字節的長度來對齊的話,代碼如下:

#include stdio.h

#pragma pack(1)

struct chji

{

char name[9];  //9

int number;    //4

char sex;      //1

double score;  //8

float aa;      //4

};

struct chji stu;

#pragma pack()

int main()

{

printf(“sizeof(struct chji)=%d\n”,sizeof(struct chji));

return 0;

}

運行結果:sizeof(struct chji)=26

即9+4+1+8+4=26,你可以查下#pragma pack()相關的資料的,就會清楚了。

關於C語言中的結構體字節對齊

仔細看一下書中的說明吧,這三言兩語介紹起來有點累

或從網上查閱相關的技術資料,有詳細描述。

一般簡單來說,結構體從第一個變量開始檢查空間的“對齊字節數”,

默認以第一個字節大小作為對齊字節數,如果遇上的下一個字節與當前對齊字節數不同時,就按兩者中較大的來進行結構體空間分配,接下來的對齊就全按此值來對齊,直到再遇上不同的才進行檢查或改變。

c語言結構體對齊的問題。

這是個好問題!

為什麼會有對齊的問題呢?簡單的說就是為了提高訪問內存的效率,這和CPU內部的機制有關,如果你想深入理解,需要閱讀 Intel 開發者手冊。對齊採用的總體原則是這樣的:4字節變量的存放要對齊到可以被4整除的地址上,8字節變量的存放要對齊到可以被8整除的地址上。其他變量類推就行了。如果沒對齊編譯器就會將某個變量的存儲往後推遲幾個字節,以保證對齊後再存放。

具體到這個問題就是可以先假設結構體變量從地址0處開始存放,那麼第一種情況就是這樣的了:

cat 存放的位置是地址0-地址3

a數組存放的位置是地址4-地址23

dog存放的位置是地址24到地址31

這裡可以看到它們都符合對齊的原則(即每個變量開始存放的地址可以除盡它們所佔的字節數),所以是32

第二種情況是這樣的:

cat仍然存放到地址0-地址3處

a數組是地址4到地址27處

存放dog時編譯器計算除下一個地址28並不能除盡double的字節數8,於是它要將地址進行遞增。29,30,31仍然不能除盡8,知道遞增到32時可以將8除盡了,所以dog變量會被存放在地址32到地址39處,從地址0到地址39正好40個字節,這就解釋了第二種情況了。

ps. 其實你這個問題還有一種變種就是一個結構體里在套一個結構體,這時會牽扯到內部的結構體對齊的問題。等你以後遇見了再給我提問吧,我給你解釋。

C語言中位域和結構體得區別是什麼?

C語言結構體對齊也是老生常談的話題了。基本上是面試題的必考題。內容雖然很基礎,但一不小心就會弄錯。寫出一個struct,然後sizeof,你會不會經常對結果感到奇怪?sizeof的結果往往都比你聲明的變量總長度要大,這是怎麼回事呢?

開始學的時候,也被此類問題困擾很久。其實相關的文章很多,感覺說清楚的不多。結構體到底怎樣對齊?

有人給對齊原則做過總結,具體在哪裡看到現在已記不起來,這裡引用一下前人的經驗(在沒有#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一下,人家就可以跟你解釋的,一大堆的道理。

最後順便提一點,在設計結構體的時候,一般會尊照一個習慣,就是把佔用空間小的類型排在前面,佔用空間大的類型排在後面,這樣可以相對節約一些對齊空間。

本篇文章來源於:開發學院 原文鏈接:

什麼是C語言結構體字節對齊,為什麼要對齊

對齊跟數據在內存中的位置有關。如果一個變量的內存地址正好位於它長度的整數倍,他就被稱做自然對齊。比如在32位cpu下,假設一個整型變量的地址為0x00000004,那它就是自然對齊的。

需要字節對齊的根本原因在於CPU訪問數據的效率問題。假設上面整型變量的地址不是自然對齊,比如為0x00000002,則CPU如果取它的值的話需要訪問兩次內存,第一次取從0x00000002-0x00000003的一個short,第二次取從0x00000004-0x00000005的一個short然後組合得到所要的數據,如果變量在0x00000003地址上的話則要訪問三次內存,第一次為char,第二次為short,第三次為char,然後組合得到整型數據。而如果變量在自然對齊位置上,則只要一次就可以取出數據。一些系統對對齊要求非常嚴格,比如sparc系統,如果取未對齊的數據會發生錯誤,舉個例:

char ch[8];

char *p = ch[1];

int i = *(int *)p;

運行時會報segment error,而在x86上就不會出現錯誤,只是效率下降。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/237592.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:05
下一篇 2024-12-12 12:06

相關推薦

  • AES加密解密算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES算法,並對實現過程進…

    編程 2025-04-29
  • 學習Python對學習C語言有幫助嗎?

    Python和C語言是兩種非常受歡迎的編程語言,在程序開發中都扮演着非常重要的角色。那麼,學習Python對學習C語言有幫助嗎?答案是肯定的。在本文中,我們將從多個角度探討Pyth…

    編程 2025-04-29
  • Python被稱為膠水語言

    Python作為一種跨平台的解釋性高級語言,最大的特點是被稱為”膠水語言”。 一、簡單易學 Python的語法簡單易學,更加人性化,這使得它成為了初學者的入…

    編程 2025-04-29
  • OpenJudge答案1.6的C語言實現

    本文將從多個方面詳細闡述OpenJudge答案1.6在C語言中的實現方法,幫助初學者更好地學習和理解。 一、需求概述 OpenJudge答案1.6的要求是,輸入兩個整數a和b,輸出…

    編程 2025-04-29
  • Vue TS工程結構用法介紹

    在本篇文章中,我們將從多個方面對Vue TS工程結構進行詳細的闡述,涵蓋文件結構、路由配置、組件間通訊、狀態管理等內容,並給出對應的代碼示例。 一、文件結構 一個好的文件結構可以極…

    編程 2025-04-29
  • Python按位運算符和C語言

    本文將從多個方面詳細闡述Python按位運算符和C語言的相關內容,並給出相應的代碼示例。 一、概述 Python是一種動態的、面向對象的編程語言,其按位運算符是用於按位操作的運算符…

    編程 2025-04-29
  • Python程序的三種基本控制結構

    控制結構是編程語言中非常重要的一部分,它們指導着程序如何在不同的情況下執行相應的指令。Python作為一種高級編程語言,也擁有三種基本的控制結構:順序結構、選擇結構和循環結構。 一…

    編程 2025-04-29
  • Python中的字節類數據

    Python作為其中一個最廣泛使用的編程語言之一,提供了多種數據類型來幫助開發者實現各種需求。在這些數據類型中,字節類數據(bytes)是一個被廣泛使用的類型。本文將會從各個方面詳…

    編程 2025-04-28
  • Python語言由荷蘭人為中心的全能編程開發工程師

    Python語言是一種高級語言,很多編程開發工程師都喜歡使用Python語言進行開發。Python語言的創始人是荷蘭人Guido van Rossum,他在1989年聖誕節期間開始…

    編程 2025-04-28
  • Python語言設計基礎第2版PDF

    Python語言設計基礎第2版PDF是一本介紹Python編程語言的經典教材。本篇文章將從多個方面對該教材進行詳細的闡述和介紹。 一、基礎知識 本教材中介紹了Python編程語言的…

    編程 2025-04-28

發表回復

登錄後才能評論