在C/C 中經常需要進行存儲器的操作,關于數據如何在存儲器中存儲的問題也是非常重要的,如何在保證數據量(信息量)的同時又保證數據的存儲量最小,乍一聽感覺沒什么好討論的。但是作為學習嵌入式的必須要明白數據的存儲是與數據的結構存在密切聯系的,特別是結構體中的內存分配問題。
首先應該明白基本的類型在內存中的大小,char型一般占有1個字節,int型一般占有4個字節,double型一般占有8個字節,short 則占有2個字節(當然也會存在一定的變化,具體情況依據編譯器決定)。我們都知道C語言的結構體是一個不同類型數據的集合。那么一個結構體到底占多少存儲空間呢?
首先應該意識到C語言的存儲存在一定的特殊性。在C語言的結構體中需要主要的是數據存儲的對齊方式。對齊主要是為了方便數據的訪問,提高計算機的處理速度,但是對齊會導致內存空間的浪費,這些浪費對于大內存空間的設備而言,沒什么必要,但是對于嵌入式系統而言會造成大量的浪費。
在32bits的系統中對一個寄存器(32bits)的訪問直接訪問,但是對于寄存器中某一個字節的訪問反而覺得很不方便,因此如果只是單個字節的訪問反而增加了系統的負擔。對一個寄存器的訪問可以通過一個起始地址來實現,但是我們在很多CPU的用戶手冊中都會發現,寄存器的起始地址都能被4整除,這就是為了提高計算速度而采取的一些默認的方式。一個寄存器一般而言占有4個bytes,那么對下一個寄存器的訪問只需要在原來的地址基礎上加上4個 bytes即可。
對齊的基本作用就是提高系統的功能,特別是訪問存儲器的能力得到提高。
對齊在使用中有較多的意義。基本的使用原則:
1、對齊是為了提高系統的訪問速度,一般基本的對齊原則是按著最大的基本類型的長度進行對齊,較小的元素可以幾個組合起來填充一段對齊內存,實現基本的對齊,但是需要滿足條件2。
2、結構體中的元素也要滿足一定的分布條件,就是元素的存儲起始地址要滿足能夠整除該元素類型的長度。
3、在結構體中存在結構體的情況下,也只是按著結構體中最大的基本類型長度對齊(包含內部結構體中的最大基本類型長度)。
在不同的編譯器之間也存在一定的差別。在linux中最大的對齊長度是 4個字節,也就是如果結構體中的最大的基本類型長度是大于4的,那么也按著4對齊,同時不會按著結構體中最大的基本類型的長度對齊,伴隨著最大基本類型元素的起始地址也不再滿足能夠被最大元素類型長度對齊的原則,而是滿足整除4即可。但如果結構體中最大的基本類型長度小于4,那么按著最大的基本類型長度對齊
但是在windows中基本上都是按著最大的基本類型長度進行對齊,和一般的原則相似。
這邊只是我的一些理解其中具體的要具體分析,在實際中建議將最大基本類型的元素放在開始的地方,然后將其他的數據按著一定的規律(能否組合起來滿足對齊條件等)定義結構體,這個規律要根據實際情況分析。
下面通過基本的代碼進行演示:
- #include<stdio.h>
- #include<stdlib.h>
- struct aa{
- char a;
- double b;
- short c;
- };
- struct bb
- {
- double a;
- short b;
- char c;
- };
- struct cc
- {
- struct bb s1;
- char s2;
- };
- struct dd
- {
- struct aa s1;
- char s2;
- };
- #pragma pack(1)
- struct ee
- {
- double a;
- short b;
- char c;
- };
- struct ff
- {
- char a;
- double b;
- short c;
- };
- #pragma pack()
- struct gg
- {
- char a;
- };
- struct jj
- {
- char a;
- short b;
- };
- int main()
- {
- printf("double size is %d %d %d\n",sizeof(double),sizeof(short),sizeof(char));
- printf("size of s1 = %d\nsize of s2 = %d\n",sizeof(struct aa),sizeof(struct bb));
- printf("size of t1 = %d\nsize of dd = %d\n",sizeof(struct cc),sizeof(struct dd));
-
- printf("size of struct ee = %d\nsize of struct ff = %d\nsize of struct gg = %d\nsize of struct jj = %d\n",
- sizeof(struct ee),sizeof(struct ff),sizeof(struct gg),sizeof(struct jj));
- exit(0);
- }
在linux下的結果:
在windows下的結果:
在linux下的存儲形式,其中黑色包圍起來的才是我們的存儲空間白色的部分是保留區域,通過下面的兩幅圖就可以知道其中的一些道理,知道其中所謂的完成一樣的功能,保證存儲空間最小:
在windows下的存儲形式,其中黑色包圍起來的才是我們的存儲空間白色的部分是保留區域:
從上面的幾個圖片可以知道在C語言中的內存分布是比較復雜的。一定要注意存儲的對齊形式,這樣才能了解其中的分布規律。當然了上面的形式都只是在小端處理器模式下的存儲形式,對于大端也有類似的情況,只是存儲的位置不一樣,但是內存的大小是相同的。
結構體的定義不能是隨便的,如果考慮好對齊關系能夠節省大量的存儲空間。實現效率和存儲空間的折中。雖然#pragma pack(n)等能夠改變其中的對齊方式,不過建議不要隨便改動,可能得不償失。