自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C 語言結(jié)構(gòu)體內(nèi)存對(duì)齊:原來是這么回事!

開發(fā)
內(nèi)存對(duì)齊看起來是個(gè)小細(xì)節(jié),但它體現(xiàn)了計(jì)算機(jī)系統(tǒng)設(shè)計(jì)的精妙之處 —— 在效率和空間使用之間尋找平衡。

大家好,我是小康。

今天咱們聊一個(gè)看似復(fù)雜實(shí)則很有意思的話題 —— C 語言中的結(jié)構(gòu)體內(nèi)存對(duì)齊。別被這個(gè)名字嚇到,我保證用最接地氣的方式帶你徹底搞懂它!

很多初學(xué)者學(xué)習(xí) C 語言時(shí)都會(huì)遇到這樣的困惑:為啥我定義的結(jié)構(gòu)體占用的內(nèi)存總是比我想象的大?明明加起來應(yīng)該是這么多字節(jié),實(shí)際卻要更多?這就是內(nèi)存對(duì)齊在搗鬼啦!

一、什么是內(nèi)存對(duì)齊?先來個(gè)生活例子

想象一下,你去超市購(gòu)物,收銀臺(tái)前排了一長(zhǎng)隊(duì)。超市為了提高效率,規(guī)定:

  • 購(gòu)買 1-3 件商品的顧客,必須站在 3 的倍數(shù)位置(第 3、6、9... 個(gè)位置)
  • 購(gòu)買 4-7 件商品的顧客,必須站在 4 的倍數(shù)位置(第 4、8、12... 個(gè)位置)
  • 購(gòu)買 8 件以上商品的顧客,必須站在 8 的倍數(shù)位置(第 8、16、24... 個(gè)位置)

這樣會(huì)怎樣?隊(duì)伍中肯定會(huì)出現(xiàn)空位!但收銀員處理起來更有效率,因?yàn)樗芸焖倥袛嗝课活櫩痛蟾判枰嚅L(zhǎng)時(shí)間。

內(nèi)存對(duì)齊就是這個(gè)道理。電腦處理不同大小的數(shù)據(jù)類型時(shí),也喜歡把它們放在特定的"位置"上,這樣處理起來更高效,即使這意味著有些內(nèi)存看起來被"浪費(fèi)"了。

二、為什么需要內(nèi)存對(duì)齊?

簡(jiǎn)單說:為了提高訪問效率。

現(xiàn)代計(jì)算機(jī)的 CPU 訪問內(nèi)存時(shí),并不是一個(gè)字節(jié)一個(gè)字節(jié)地讀取,而是一次讀取固定大小的塊(比如 4 字節(jié)或 8 字節(jié))。如果你的數(shù)據(jù)剛好在這些塊的邊界上,那訪問起來就很高效;如果數(shù)據(jù)跨越了邊界,CPU 就需要多讀幾次,效率自然就低了。

就像你去圖書館借書,管理員一次能搬運(yùn) 8 本書。如果你要的書剛好擺在 8 本一組的架子上,取起來就很方便;如果你的書跨了兩組,管理員就得跑兩趟,多費(fèi)勁啊!

三、對(duì)齊規(guī)則:簡(jiǎn)單又有趣

C 語言的內(nèi)存對(duì)齊遵循三個(gè)基本規(guī)則:

  • 每個(gè)成員相對(duì)于結(jié)構(gòu)體起始位置的偏移量必須是自身大小的整數(shù)倍
  • 結(jié)構(gòu)體的總大小必須是最大成員大小的整數(shù)倍
  • 結(jié)構(gòu)體大小至少是所有成員大小之和,再加上為滿足前兩條規(guī)則所需的填充字節(jié)

這聽起來有點(diǎn)復(fù)雜?別急,我畫個(gè)圖,保證你一看就懂!

四、來個(gè)直觀的例子

假設(shè)我們有這樣一個(gè)結(jié)構(gòu)體:

struct Example {
    char a;     // 1字節(jié)
    int b;      // 4字節(jié)
    char c;     // 1字節(jié)
};

按理說,這個(gè)結(jié)構(gòu)體應(yīng)該占用 1 + 4 + 1 = 6 字節(jié),對(duì)吧?但實(shí)際上它占用了 12 字節(jié)!為什么?

讓我們用圖來表示內(nèi)存布局:

字節(jié)位置: 0  1  2  3  4  5  6  7  8  9  10 11
內(nèi)存內(nèi)容: a  -  -  -  b  b  b  b  c  -  -  -
            |-填充-|                 |-填充-|

解釋一下:

  • a 占用第0個(gè)字節(jié)
  • 由于 b 是 int 類型(4字節(jié)),按對(duì)齊規(guī)則它的起始位置必須是 4 的整數(shù)倍,所以跳過 1-3 字節(jié)(填充3個(gè)字節(jié)),從第 4 個(gè)字節(jié)開始
  • b 占用第 4-7 字節(jié)
  • c 占用第 8 個(gè)字節(jié)
  • 最后,整個(gè)結(jié)構(gòu)體的大小必須是其最大成員(這里是int,4字節(jié))的整數(shù)倍,所以還要填充到 12 字節(jié)

五、調(diào)整順序可以節(jié)省空間

聰明的你可能已經(jīng)想到了:如果我們調(diào)整結(jié)構(gòu)體成員的順序,是不是就能減少這些"浪費(fèi)"的填充字節(jié)呢?

沒錯(cuò)!看這個(gè)例子:

struct BetterExample {
    int b;      // 4字節(jié)
    char a;     // 1字節(jié)
    char c;     // 1字節(jié)
};

現(xiàn)在的內(nèi)存布局變成了:

字節(jié)位置: 0  1  2  3  4  5  6  7
內(nèi)存內(nèi)容: b  b  b  b  a  c  -  -
                           |填充|

通過簡(jiǎn)單地調(diào)整順序,結(jié)構(gòu)體大小從 12 字節(jié)減少到了 8 字節(jié)!是不是很神奇?

六、實(shí)戰(zhàn):驗(yàn)證我們的理解

來寫個(gè)小程序驗(yàn)證一下(32位系統(tǒng)下):

#include <stdio.h>

struct Example1 {
    char a;     // 1字節(jié)
    int b;      // 4字節(jié)
    char c;     // 1字節(jié)
};

struct Example2 {
    int b;      // 4字節(jié)
    char a;     // 1字節(jié)
    char c;     // 1字節(jié)
};

int main() {
    printf("Example1大小: %lu字節(jié)\n", sizeof(struct Example1));
    printf("Example2大小: %lu字節(jié)\n", sizeof(struct Example2));
    return0;
}

運(yùn)行結(jié)果:

Example1大小: 12字節(jié)
Example2大小: 8字節(jié)

看吧,和我們分析的完全一致!

七、如何手動(dòng)控制對(duì)齊方式?

有時(shí)候,我們可能需要更精確地控制內(nèi)存對(duì)齊,C語言提供了幾種方法:

(1) 使用編譯器指令:

#pragma pack(1)  // 設(shè)置按1字節(jié)對(duì)齊
struct CompactExample {
    char a;
    int b;
    char c;
};
#pragma pack()   // 恢復(fù)默認(rèn)對(duì)齊

(2) 使用屬性聲明(GNU C):

struct CompactExample {
    char a;
    int b;
    char c;
} __attribute__((packed));

這兩種方法都能讓我們的 CompactExample 結(jié)構(gòu)體嚴(yán)格占用 6 字節(jié),沒有任何填充。但要注意,這樣做可能會(huì)降低程序的運(yùn)行效率,特別是在某些對(duì)內(nèi)存對(duì)齊要求嚴(yán)格的 CPU 架構(gòu)上。

八、實(shí)際應(yīng)用:為什么要關(guān)心內(nèi)存對(duì)齊?

嵌入式系統(tǒng)和內(nèi)存受限場(chǎng)景:在資源緊張的環(huán)境中,合理安排結(jié)構(gòu)體成員順序可以節(jié)省大量?jī)?nèi)存。

  • 網(wǎng)絡(luò)通信和文件IO:不同系統(tǒng)可能有不同的對(duì)齊方式,傳輸數(shù)據(jù)時(shí)需要考慮這一點(diǎn)。
  • 提高程序性能:了解內(nèi)存對(duì)齊可以幫助你寫出更高效的代碼。

小結(jié):看完是不是覺得相見恨晚?

內(nèi)存對(duì)齊看起來是個(gè)小細(xì)節(jié),但它體現(xiàn)了計(jì)算機(jī)系統(tǒng)設(shè)計(jì)的精妙之處 —— 在效率和空間使用之間尋找平衡。掌握了這個(gè)知識(shí)點(diǎn),你就能:

  • 理解為什么有時(shí)候結(jié)構(gòu)體大小和你預(yù)計(jì)的不一樣
  • 通過合理安排成員順序優(yōu)化內(nèi)存使用
  • 在需要時(shí)手動(dòng)控制對(duì)齊方式
  • 寫出更高效、更專業(yè)的代碼

怎么樣,是不是覺得這個(gè)知識(shí)點(diǎn)其實(shí)挺簡(jiǎn)單,又特別實(shí)用?希望這篇文章能幫你徹底搞懂 C 語言結(jié)構(gòu)體內(nèi)存對(duì)齊這個(gè)看似復(fù)雜的概念!

責(zé)任編輯:趙寧寧 來源: 跟著小康學(xué)編程
相關(guān)推薦

2021-07-29 16:56:59

微信騰訊注冊(cè)

2020-06-30 08:12:32

VMwareKVMDocker

2022-08-15 08:01:00

三色標(biāo)記JVM算法

2022-10-21 08:17:13

MongoDB查詢Document

2018-06-04 08:40:20

磁盤分區(qū)MBR

2021-02-07 08:13:18

@DateTimeFo@NumberFormSpring

2020-03-04 08:47:10

Kafka架構(gòu)原理

2020-02-23 15:55:00

疫情AI人工智能

2020-11-12 07:32:53

JavaScript

2021-02-11 09:14:36

內(nèi)存虛擬機(jī)數(shù)據(jù)

2020-06-12 10:46:18

C語言棧內(nèi)存結(jié)構(gòu)體

2022-01-14 14:19:38

ReactTS前端

2024-10-11 11:59:03

2011-05-25 09:58:46

C#

2012-01-11 09:15:45

Objective-C

2017-06-06 15:13:07

2020-06-17 14:13:29

索引數(shù)據(jù)庫(kù)場(chǎng)景

2023-04-09 23:25:30

Java注解元注解

2009-03-10 12:42:45

2014-03-31 14:59:08

大數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)