最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言結(jié)構(gòu)體內(nèi)存的對(duì)齊知識(shí)詳解

 更新時(shí)間:2021年03月08日 09:46:47   作者:guguguhuha  
這篇文章主要介紹了C語言結(jié)構(gòu)體內(nèi)存的對(duì)齊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在前面的章節(jié)中,我們談到了C語言中整數(shù)以及浮點(diǎn)數(shù)的儲(chǔ)存

今天,我們來談一談一些關(guān)于結(jié)構(gòu)體內(nèi)存的知識(shí)。

我們先來看一個(gè)例子:

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

大家來猜猜這個(gè)結(jié)構(gòu)體S1的內(nèi)存是多少?

相信會(huì)有人給出 6 的結(jié)果,他們或許是這樣想的,兩個(gè) char 類型分別為一個(gè)字節(jié),一個(gè) int 類型又為4個(gè)字節(jié),加起來剛好為6個(gè)

但是

結(jié)果真是如此嗎?

我們來看看運(yùn)行結(jié)果:

為什么呢,接下來我們就引出正文。

一.結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則

首先,正如引例所示,結(jié)構(gòu)體的內(nèi)存并不是簡簡單單的將結(jié)構(gòu)體各個(gè)成員的大小相加。

結(jié)構(gòu)體的大小往往遵循著結(jié)構(gòu)體的對(duì)齊規(guī)則:

  1. 第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。
  2. 其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。
  3. 結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
  4. 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。

這里要注意的一點(diǎn)就是要解釋一下這個(gè)對(duì)齊數(shù)的概念

對(duì)齊數(shù):編譯器默認(rèn)的一個(gè)對(duì)齊數(shù) 與 該結(jié)構(gòu)體變量成員自身大小的較小值。

  注:

    不是所有的編譯器都有自己默認(rèn)的對(duì)齊數(shù)。

    在VS下其默認(rèn)的對(duì)齊數(shù)為8

    在linux下的默認(rèn)值為4

二.怎樣計(jì)算結(jié)構(gòu)體的大小

在講計(jì)算之前,我們繼續(xù)來看一看上面的那個(gè)例子:

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stddef.h>

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

int main()
{
 printf("該結(jié)構(gòu)體成員 c1 開始的位置為第 %d 個(gè)字節(jié)\n", offsetof(struct S1, c1));
 printf("該結(jié)構(gòu)體成員 i 開始的位置為第 %d 個(gè)字節(jié)\n", offsetof(struct S1, i));
 printf("該結(jié)構(gòu)體成員 c2 開始的位置為第 %d 個(gè)字節(jié)\n", offsetof(struct S1, c2));
 printf("該結(jié)構(gòu)體所占的內(nèi)存空間為 %d 個(gè)字節(jié)\n", sizeof(struct S1));
 return 0;
}

注:

  宏 offsetof() 可以計(jì)算出結(jié)構(gòu)體各成員所相對(duì)開始位置的一個(gè)偏移量。

  偏移量 : 我們可以理解為把結(jié)構(gòu)體變量第一個(gè)成員所儲(chǔ)存的第一個(gè)位置置于0,以此遞增

我們來看看結(jié)果:

這是為什么呢?

我們來看看上面所提到的結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則:

然后我們來看示意圖:

此時(shí),關(guān)于結(jié)構(gòu)體的大小,我們應(yīng)該清楚了不少,接下來,我們繼續(xù)來看幾道例題:

struct S2
{
 char c1;
 char c2;
 int i;
};
int main()
{
 printf("%d\n", sizeof(struct S2));
 return 0;
 }

我們看到,S1與S2的區(qū)別僅僅只是調(diào)換了一下各成員間的順序,那它所占的內(nèi)存還是剛才的值嗎:

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

我們繼續(xù)來分析一下:

趁此機(jī)會(huì),我們?cè)賮盱柟桃幌拢?/p>

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

int main()
{
  printf("%d\n", sizeof(struct S3));
  return 0;
}

它的結(jié)果會(huì)是多少呢?

不知道大家作對(duì)了嗎?

解析:

   首先 double 類型占8個(gè)字節(jié)

  char 又展覽接下來的一個(gè)

  而 int 的對(duì)齊數(shù)為 4,所以空3個(gè)字節(jié)從12開始

  而這個(gè)結(jié)構(gòu)體的最大對(duì)齊數(shù)為8

   所以該結(jié)構(gòu)體占 2*8 = 16個(gè)字節(jié)

最后,我們?cè)賮砜匆坏狼短捉Y(jié)構(gòu)體的例題:

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

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

int main()
{
  printf("%d\n", sizeof(struct S4));
  return 0;
}

它的結(jié)果又為多少呢?

解析:

  我們先來看看規(guī)則 4: 如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,

            結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍

  S3的最大對(duì)齊數(shù)為 8,它的大小為 16 個(gè)字節(jié)

  首先,毋庸置疑的是 char 先放到首位

   接下來因?yàn)镾3的對(duì)齊數(shù)為 8,所以S3放在了以位置8開始的16個(gè)字節(jié)

   最后是double,對(duì)齊數(shù)為8,所以放在了24的位置

  最后,該結(jié)構(gòu)體的大小為 4*8 = 32 個(gè)字節(jié)

在進(jìn)行結(jié)構(gòu)體所占大小的計(jì)算中,我們又可以得到一個(gè)基本編程常識(shí):

三.設(shè)計(jì)結(jié)構(gòu)體時(shí)要注意的方面

在我們進(jìn)行結(jié)構(gòu)體的設(shè)計(jì)中,我們可以把一些所占空間小的,來湊到一起,提高資源的利用率。

正如上文所提到的例1與例2,結(jié)構(gòu)體成員完全相同,但順序不同,兩個(gè)結(jié)構(gòu)體的大小也截然不同

//例1
struct S1
{
  char c1;
  int i;
  char c2;
};

//例2
struct S2
{
  char c1;
  char c2;
  int i;
};

int main()
{
  printf("%d\n", sizeof(struct S1));//12
  printf("%d\n", sizeof(struct S2));//8
  return 0;
}

四.為什么存在內(nèi)存對(duì)齊

對(duì)于這個(gè)原因,目前話沒有一種完全正確的答案,但是:

大部分的參考資料都是如是說的:

  1. 平臺(tái)原因(移植原因):

    不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;

    某些硬件平臺(tái)只能在某些地址 處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。

   2. 性能原因:

     數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。

    原因在于,為了訪問未對(duì)齊的內(nèi)存,處理器 需要作兩次內(nèi)存訪問;而對(duì)齊的內(nèi)存訪問僅需要一次訪問。

對(duì)于原因而我們來看一個(gè)示意圖:

 

五.修改默認(rèn)對(duì)齊數(shù)

我們通常使用如下的預(yù)處理命令來修改編譯器的默認(rèn)對(duì)齊數(shù):

#pragma pack()  

如果()里面不加數(shù)字,則默認(rèn)為編譯器的默認(rèn)對(duì)齊數(shù)

我們修改的時(shí)候,只需在()里加一個(gè)數(shù)字就行

取消的時(shí)候再添加一次#pragma pack() 即可

注:

  再()里添加的數(shù)字,我們通常加的都是2的多少次方

下面來舉一個(gè)實(shí)例:

#include <stdio.h>
#pragma pack(8)//設(shè)置默認(rèn)對(duì)齊數(shù)為8
struct S1
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)
#pragma pack(1)//設(shè)置默認(rèn)對(duì)齊數(shù)為8
struct S2
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)
int main()
{
  //輸出的結(jié)果是什么?
  printf("%d\n", sizeof(struct S1));//12
  printf("%d\n", sizeof(struct S2));//6
  return 0;
}

由此可見,我們也可以通過修改默認(rèn)對(duì)齊數(shù)來節(jié)約 結(jié)構(gòu)體使用的空間。

關(guān)于結(jié)構(gòu)體內(nèi)存的講解便到此為止。

筆者水平有限,若有錯(cuò)誤之處,還望多多指正。

總結(jié)

到此這篇關(guān)于C語言結(jié)構(gòu)體內(nèi)存對(duì)齊的文章就介紹到這了,更多相關(guān)C語言結(jié)構(gòu)體內(nèi)存對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++哈希應(yīng)用之位圖,哈希切分與布隆過濾器詳解

    C++哈希應(yīng)用之位圖,哈希切分與布隆過濾器詳解

    這篇文章主要為大家詳細(xì)介紹了C++哈希應(yīng)用中的位圖、哈希切分與布隆過濾器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以參考一下
    2023-04-04
  • Unity3D實(shí)現(xiàn)經(jīng)典小游戲Pacman

    Unity3D實(shí)現(xiàn)經(jīng)典小游戲Pacman

    這篇文章主要介紹了基于Unity3D制作一做個(gè)經(jīng)典小游戲Pacman,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Unity3D有一定的幫助,感興趣的小伙伴可以了解一下
    2021-12-12
  • C語言鏈表實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    C語言鏈表實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言鏈表實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • C語言 語義陷阱超詳細(xì)梳理總結(jié)

    C語言 語義陷阱超詳細(xì)梳理總結(jié)

    這篇文章主要介紹了C語言常見的一些語義陷阱,梳理的比較全面,對(duì)我們做開發(fā)的過程中有一定幫助,感興趣的朋友快來看看吧
    2022-03-03
  • C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串)

    C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 用C++來解決3*3拼圖的問題

    用C++來解決3*3拼圖的問題

    這篇文章主要介紹了用C++來解決3*3拼圖的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Qt中正則表達(dá)式的常見用法(QRegularExpression類)

    Qt中正則表達(dá)式的常見用法(QRegularExpression類)

    正則表達(dá)式即一個(gè)文本匹配字符串的一種模式,Qt中使用QRegExp類進(jìn)行模式匹配,下面這篇文章主要給大家介紹了關(guān)于Qt中正則表達(dá)式的常見用法,文中介紹的是QRegularExpression類的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • C++數(shù)據(jù)封裝以及定義結(jié)構(gòu)的詳細(xì)講解

    C++數(shù)據(jù)封裝以及定義結(jié)構(gòu)的詳細(xì)講解

    這篇文章主要詳細(xì)講解了C++數(shù)據(jù)封裝以及定義結(jié)構(gòu),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • QT5?Thread線程的具體實(shí)現(xiàn)

    QT5?Thread線程的具體實(shí)現(xiàn)

    本文主要介紹了QT5?Thread線程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++回文數(shù)及素?cái)?shù)問題計(jì)算方法

    C++回文數(shù)及素?cái)?shù)問題計(jì)算方法

    這篇文章主要介紹了C++回文數(shù)及素?cái)?shù)問題計(jì)算方法,可實(shí)現(xiàn)一定范圍內(nèi)的素?cái)?shù)與回文數(shù)運(yùn)算功能,涉及C++字符串遍歷與數(shù)字?jǐn)?shù)學(xué)運(yùn)算的相關(guān)技巧,需要的朋友可以參考下
    2016-05-05

最新評(píng)論

大荔县| 高要市| 怀远县| 洛南县| 星子县| 通州区| 隆子县| 长丰县| 新民市| 婺源县| 城固县| 浦东新区| 隆回县| 泽普县| 墨竹工卡县| 西乡县| 阜康市| 麦盖提县| 两当县| 施秉县| 喜德县| 武宣县| 瑞昌市| 灵石县| 闸北区| 南部县| 平顺县| 莆田市| 建瓯市| 池州市| 昭通市| 望城县| 灵武市| 襄城县| 射洪县| 香港 | 裕民县| 曲靖市| 南川市| 霍林郭勒市| 衢州市|