1樓:「已登出」
要對齊啊,首先任何型別不做對齊聲明的話,長度為字長的倍數。型別在父型別中的開始位置為自己長度的倍數,在s1中 ,a開始位置為1的倍數,b開始位置為4的倍數,c開始位置為2的倍數,因此a的偏移為0,b為4-7,c為8-9,整個結構體需要長度為12
2樓:宅學部落-王利濤
為了簡化 CPU 和記憶體 RAM 之間的介面和硬體設計。比如乙個32位的計算機系統,CPU 讀取記憶體時,硬體設計上可能只支援4位元組或4位元組倍數對齊的位址訪問,CPU 每次往記憶體 RAM 讀寫資料時,乙個週期可以讀寫4個位元組。如果我們把乙個資料放在4位元組對齊的位址上,那麼CPU一次就可以把資料讀寫完畢;如果我們把乙個 int 型資料放在乙個非4位元組對齊的位址上,那 CPU 就要分2次才能把這個4位元組大小的資料讀寫完畢。
為了配合計算機的硬體設計,編譯器在編譯程式時,對於一些基本資料型別,比如 int、char、short、float 等,會按照其資料型別的大小進行位址對齊,按照這種位址對齊方式分配的儲存位址,CPU 一次就可以讀寫完畢。雖然邊界對齊會造成一些記憶體空洞,浪費一些記憶體單元,但是在硬體上的設計卻大大簡化了。這也是編譯器給我們定義的變數分配位址時,不同型別變數按不同位元組數字址對齊的原因。
除了 int、char、short、float 這些基本型別資料,對於一些復合型別資料,也要滿足位址對齊要求。
結構體作為一種復合資料型別,編譯器在給乙個結構體變數分配儲存空間時,不僅要考慮結構體內各個基本成員的位址對齊,還要考慮結構體整體的對齊。為了結構體內的成員位址對齊,編譯器可能會在結構體內填充一些空間;為了結構體整體對齊,編譯器可能會在結構體的末尾填充一些空間。
接下來,我們定義乙個結構體,結構體內定義 int、char 和 short 三種成員,並列印結構體的大小和各個成員的位址。
struct
data
intmain
(void
)程式執行結果如下。
size: 12
&s.a: 0028FF30
&s.b: 0028FF34
&s.c: 0028FF38
我們可以看到,因為結構體的成員 b 需要4位元組對齊,編譯器在給成員 a 分配完空間後,接著會空出3個位元組,在滿足4位元組對齊的 0x0028FF34 位址處才給成員 b 分配儲存空間。接著是 short 型別的成員 c 佔據2位元組的儲存空間。三個結構體成員一共佔據4+4+2=10位元組的儲存空間,根據結構體的對齊規則,結構體的整體對齊要向結構體所有成員中最大對齊位元組數或其整數倍對齊,或者說結構體的整體長度要為其最大成員位元組數的整數倍,如果不是整數倍要補齊。
因為結構體最大成員 int 為4個位元組,或者說按4位元組的整數倍對齊,所以結構體的長度要為4的整數倍,要在結構體的末尾補充2個位元組,所以最後結構體的 size 為12個位元組。
結構體成員中,不同的排放順序,可能也會導致結構體的整體長度不一樣,我們修改一下上面的程式。
struct
data
;int
main
(void
)程式執行結果如下。
size:8
&s.a
:0028FF30&
s.b:
0028FF32&
s.c:
0028FF
34我們調整了一些成員順序,你會發現,char 型變數 a 和 short 型變數 b,分配在了結構體的前4個位元組儲存空間中,而且都滿足各自的位址對齊,整個結構體大小是8位元組,只造成乙個位元組的記憶體空洞。我們繼續修改程式,讓 short 型的變數 b 按4位元組對齊:
struct
data
;程式執行結果如下。
size:12
&s.a
:0028FF30&
s.b:
0028FF34&
s.c:
0028FF
38你會發現,結構體的大小又重新變為12個位元組。這是因為,我們顯式指定 short 變數以4位元組位址對齊,導致變數 a 的後面填充了3個位元組空間。int 型變數 c 也要4位元組對齊,所以變數 b 的後面也填充了2個位元組,導致整個結構體的大小為12位元組。
我們不僅可以顯式指定結構體內某個成員的位址對齊,也可以指定整個結構體的對齊方式。
struct
data
__attribute__
((aligned(16
)));
程式執行結果如下。
size:16
&s.a
:0028FF30&
s.b:
0028FF32&
s.c:
0028FF
34在這個結構體中,各個成員一共佔8個位元組。通過前面學習我們知道,整個結構體的對齊只要是最大成員對齊位元組數的整數倍即可。所以這個結構體整體就以8位元組對齊,結構體的整體長度為8位元組。
但是我們在這裡,顯式指定結構體整體以16位元組對齊,所以編譯器就會在這個結構體的末尾填充8個位元組以滿足16位元組對齊的要求,導致結構體的總長度變為16位元組。
嵌入式C語言自我修養 07:位址對齊那些事兒
3樓:
試試這樣寫
#pragma pack(1)
struct st1 ...
struct st2 ...
#pragma pack()
#include
你會發現兩者sizeof一樣了,然後去了解下"記憶體對齊"。
憶臻:C/C++記憶體對齊詳解
如何理解 struct 的記憶體對齊?
4樓:Mimosa
這裡引發乙個資料結構定義中的位對齊問題,而位對齊又牽涉到記憶體分頁需要,記憶體是按頁管理,每乙個頁一般是4K,如果發生基本資料的位元組在乙個頁面不完整,也就是跨頁了,會出現系統運算元據異常,雖然不會引起程式崩潰,但是會額外消耗時間讓系統訪問這樣的資料。
5樓:TravorLZH
如果你用的是gcc,可以考慮這樣定義結構體:
struct
struc
__attribute__
((packed
));這還是我之前寫自己的小作業系統時踩過的坑
6樓:朱涵俊
預設情況下,struct成員會以sizeof(成員)對齊,比如short 2位元組對齊,int 4位元組對齊,long(64位)8位元組對齊。而且整個大小是跟cpu位數相關的倍數,比如32位系統是4位元組的倍數,64位系統是8位元組的倍數。
第乙個char a無需對齊,int b 4位元組對齊,由於char a占去乙個位元組,因此b另外新開乙個4位元組空間,前面空3位元組。c前面無需空,後面空2位元組。總共12位元組。
第二個short c先2位元組對齊,char a無需對齊,跟在short c後面。int b 4位元組對齊,前面空1個位元組,總共8位元組。
可以加__attribute__((packed)),強制壓縮。
7樓:GodIsALoli
因為早期cpu的data bus是32位的。也就是說,一次從記憶體中讀出32位資料,四個位元組。四位元組也叫乙個word。
cpu提供了一種抽象,彷彿每個位元組都可以隨機訪問,但其實cpu只能隨機訪問word,不能跨word訪問。為啥設計成這樣,因為這樣做電路簡單。我個人認為現在的cpu應該完全可以做到按位元組訪問。
乙個char是八位,乙個int是32位,不能放到乙個word裡,所以char被擴充套件成了32位,int放到下乙個word裡。如果跨word訪問,需要cpu訪問兩次記憶體(邏輯上),所以用空間換時間了。
如果char後面是short,那麼這兩個變數可以放到乙個word裡。
其他答主說什麼按位元組對齊,這種說法是錯誤的,按位元組對齊其實就是每個位元組都可以被隨機訪問,所以就沒有記憶體對齊這種說法了。這種按word對齊的方式必然保證所有成員的位址是4的倍數
8樓:co lin
這樣寫就變成一樣了:
#pragma pack(push)
#pragma pack(1)
struct
st1;
struct
st2;
#pragma pack(pop)
9樓:丁冬
C 設計上存在遺憾。
當前只保證順序不保證 padding 策略(標準甚至沒有禁止對齊必要之外的 padding,意味著你拿 alignof 和 max_align 算出來的也是依賴實現定義的)不上不下怪難受的。當你對順序有要求的時候,難免也得依賴實現定義的對齊和 padding 策略了,說實話成員順序先後這種保證是現在這樣單獨放標準裡還是都丟給實現定義就現狀來說區別不大(除了第乙個成員頂頭放),反而是導致了我不依賴布局的情況下如果期望緊湊還得人肉精打細算,沒有編譯器會幫我優化順序。
當然更優解是 attribute 開關控制。C 標準也有 attribute 了。
C語言中如何定義可移植的結構體?
專案裡經常遇到類似的情況。我們通常都使用巨集來解決。如 struct myStruct 成員變數型別統一使用 S16 16位有符號數 U16 16位無符號數 S32 32位有符號數 U32 32位無符號數 吳才澤 在真正的多平台移植過程中,結構體定義的可移植性反而不太關注,要關注的是程式本身的可移植...
請問,c語言中的一句和一行兩個概念相同嗎。
一般來說語句是按照分號或者一對大括號來辨識的。在你這裡一句只是個文字遊戲。而程式設計不是咬文嚼字,所以你可以隨便改。如果老師說或者答案書上說你錯了。你就聽老師的。對於語句的瞭解你可以看這裡 https en.cppreference.com w c language statements State...
為什麼很多歐洲語言中 九 和 新 兩個詞都很像?它們是否同源?
我來模擬下舉個例子哈,為啥漢語各個方言裡的 新 和 心 這麼像啊?是同源嗎?你看官話都是 xin,粵語乙個是 san 乙個是 sam,閩南 sin,sim。傳到北韓是 sin,sim 隨便換,高和溝,多和都 我敢說全國無數方言,差異大到聽不懂,但是這裡押韻的字,其他地方大都押韻,這裡聲母相同的字,其...