【C進階】內存對齊

碼字不易,對你有幫助 點贊/轉發/關注 支持一下作者
微信搜公衆號:不會編程的程序圓
看更多幹貨,獲取第一時間更新

零 前言

自定義類型也就是:結構體,聯合和枚舉。這部分的基礎知識在前面的文章中我們也詳細的講過。點擊閱讀

我們這一節主要來講一相關的些比較重要的知識。

一 結構體

1. 內存對齊

Ⅰ)引入
struct S1
{
	char c1;
	int i;
	char c2;
};

上面是一個結構體,也是我們自定義的一種類型。我們知道,任何類型都有大小,那麼結構體 S1 的大小是多少?

是結構體各成員變量大小的和嗎?如果是的話,那結構體 S1 的大小就是 6

那我們設計一個程序驗證一下:

int main(void) {

	printf("%d", sizeof(struct S1));

	return 0;
}

輸出是:12,這個 12 是怎麼得來的呢?

想要知道這個問題答案,那我們就要了解一下 內存對齊

Ⅱ)爲什麼要內存對齊?

內存對齊關係到 CPU 讀取數據的效率 和 一些其他原因。我們這裏不做展開,有興趣可以自己查一下。

Ⅲ)規則
  • 第一個成員在與結構體變量偏移量爲0的地址處。

  • 其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。

對齊數 = 編譯器默認的一個對齊數 與 該成員大小的較小值
VS中默認的值爲8

  • 結構體總大小爲最大對齊數(每個成員變量都有一個對齊數)的整數倍。

  • 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。

四)練習

判斷下面結構體的大小:

VS 默認的對齊數是 8,32 位機器

1

struct S1
{
	char c1;
	int i;
	char c2;
};

解析:1(char) (+3(int 應該對齊到 4 的整數倍上,也就是 4,所以應該給 1 加上 3 湊成 4)) +4(int) +1(char) (+3最後整個結構體大小爲最大對齊數(也就是 4)的整數倍處,所以結構體的大小不是 9 而是 12 )(最大對齊數是最大成員的對齊數,這個是前面算過的(成員大小和默認對齊數取小))

答案:12

2

struct S2
{
	char c1;
	char c2;
	int i;
};

第一個例題已經詳細的分析了判斷結構體大小的步驟,下面不再贅述。

1 (char)+ 1 (char) (+2) + 4 (int)

答案:8

3

struct S3
{
	double d;
	char c;
	int i;
}

8 (double) + 1 (char) (+3) + 4 (int)

答案:16

4

struct S3
{
	double d;
	char c;
	int i;
};

struct S4
{
	char c1;
	struct S3 s3;
	double d;
};

例 3 中,我們已經知道了 S3 的大小是 16

1 (char) (+ 7(結構體大小是 16 和 編譯器默認對齊數 8 取較小值,所以結構體要對齊的整數倍是 8)) + 16 (S3) + 8 (double)

答案:32

不確定你可以自己在你的編譯器上敲一下,看看運行結構,前提是編譯器的默認對齊數是 8 ,如果不是,結果可能會不一樣,那麼編譯器的默認對齊數可以修改嗎?

2. 修改默認對齊數

只需要加上一條指令即可:

#pragma pack(4)//設置默認對齊數爲4

如果你想取消設置的默認對齊數,還原爲默認:

#pragma pack()

二 位段

1.瞭解位段

位段的聲明和結構是類似的,有兩個不同:

  1. 位段的成員必須是 int、unsigned int 或signed int 。
  2. 位段的成員名後邊有一個冒號和一個數字。

struct S
{
	char a : 3;// a 的大小爲 3 個比特位
	char b : 4;
	char c : 5;
	char d : 4;
};
int main(void) {

	struct S s = { 0 };
	
	// 可以像一般的結構體成員訪問一樣訪問它們
	s.a = -4;// 3 個字節存儲數的範圍是 -4 ~ 3
	s.b = 7;
	s.c = 3;
	s.d = 4;


	printf("%d\n", s.a);

	return 0;
}

存儲方式:

  1. 位段的成員可以是 int unsigned int signed int 或者是 char (屬於整形家族)類型
  2. 位段的空間上是按照需要以4個字節( int )或者1個字節( char )的方式來開闢的。
  3. 位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應該避免使用位段

位段的應用:

可以自行了解IP數據報格式


在 Github 上看更全的目錄:

https://github.com/hairrrrr/C-CrashCourse

以後的這個系列的代碼都會上傳上去,歡迎 star


以上就是本次的內容。

如果文章有錯誤歡迎指正和補充,感謝!

最後,如果你還有什麼問題或者想知道到的,可以在評論區告訴我呦,我可以在後面的文章加上你們的真知灼見​​。

關注我,看更多幹貨!

我是程序圓,我們下次再見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章