欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C語言如何計算結構體大小(結構體的內存對齊)

 更新時間:2023年07月21日 10:10:18   作者:可涵不會debug  
結構體的內存對齊是有關結構體內容的很重要一個知識點,主要考察方式是計算結構體的字節(jié)大小,所以本文就給大家詳細介紹一下C語言如何計算結構體大小,文中的代碼示例介紹的非常詳細,需要的朋友可以參考下

引言:

當我們對計算結構體一無所知,我們不妨自己思索如何計算,是不是直接計算結構體成員變量占用內存的大小呢?

那我們先舉個例子

struct s1
{
	int i;
	char a;
	char b;
};
struct s2
{
	char a;
	int i;
	char b;
};
int main()
{
	printf("%d\n", sizeof(struct s1));
	printf("%d\n", sizeof(struct s2));
	return 0;
}

觀察發(fā)現結構體的大小計算跟我們想的很不一樣。

不應該是兩個char類型,一個int類型,2*1+4答案不應該是6嗎?

上面兩個結構體內容是一樣的,只有順序不一樣,為何計算結果不一樣呢?

我們就帶著以上的疑問去探索!

一、計算偏移量

我們要研究明白結構體的成員列表在內存中到底是如何存儲的,首先要知道結構體的各個成員變量在內存中相較于起始位置的偏移量。這時候要引用到offsetof,這個宏可以計算結構體成員相較于結構體起始位置的偏移量。

使用宏offsetof

 如何使用宏offsetof?

首先有頭文件:#include<stddef.h>

參數是類型,和成員名,返回值就是結構體成員相較于結構體起始位置的偏移量。

我們先試著打印下s2各個成員關于結構體起始位置的偏移量。

發(fā)現結果是0、4、8,我們可以畫一張內存圖進行理解。

如圖所示,根據offsetof我們可以得到這樣的內存存儲模式,但是這樣一共也就9個字節(jié),后面的3個字節(jié)從何而來?中間多出來的3個字節(jié)又從何而來?

我們繼續(xù)探索。

結構體到底如何計算?

二、結構體的對齊規(guī)則

我們經過上面的分析,發(fā)現結構體成員不是按照順序在內存中連續(xù)存放的,而是有一定的對齊規(guī)則,接下來我們就研究結構體的內存規(guī)則。

  • 結構體的第一個成員永遠放在相較于結構體變量的起始未知的偏移量為0的位置
  • 從第二個成員開始,往后的每個成員都要對齊到某個對齊數的整數倍處。(對齊數:結構體成員自身大小和默認對齊數的較小值)VS上默認對齊數是8,gcc沒有默認對齊數,對齊數就是變量本身的大小。
  • 結構體的總大小,必須是最大對齊數的整數倍,最大對齊數是:所有成員的對齊數中最大的值
  • 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。

三、總結計算方法

我們首先要知道結構體變量成員的自身字節(jié)大小,然后去尋找對齊數,對齊數的尋找方法就是將自身字節(jié)大小和默認對齊數比較,取較小值,這樣先找到對齊數,然后根據自身的字節(jié)大小去填充,就完成了成員在內存中的存儲,最后在所有的成員已經結束存儲,再計算最大對齊數(所有成員的對齊數中最大值),這樣就完成了計算!

我們既然已經知道規(guī)則和計算方法,就讓我們小試牛刀一下~

四、練習

練習一:

struct s3
{
	double d;
	char c;
	int i;
};
int main()
{
	printf("%d\n", sizeof(struct s3));
	return 0;
}

上面圖片的寫法就是左邊是本身成員變量的字節(jié)大小,右邊是默認對齊數進行比較,最后再從對齊數中找出最大值,就是最大對齊數,所以最后0~15就是存儲結構體的大小,也就是一共16個字節(jié)

 練習二:

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;
}

上面是嵌套結構體場景,結構體S3本身大小是16,需要對齊到自身最大對齊數的位置,也就是8,然后double類型的對齊數是8,最后總字節(jié)大小也滿足最大對齊數,所以一共32個字節(jié)。

五、為什么存在內存對齊?

1、平臺原因

不是所有的硬件平臺都能訪問任意地址上的任意數據;某些平臺只能在某些地址處取某些地址處取特定類型的數據,否則拋出硬件異常

2、性能原因

數據結構(尤其是棧)應該盡可能在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。

總體來說

結構體的內存對齊,就是讓空間換時間。 

TIP:

我們在設計結構體時,可以人為的節(jié)省空間——讓占用空間小的成員盡量集中在一起。

例如我們之前舉的例子,盡管兩個結構體存的成員變量一樣,但是順序不一樣,結構體內存大小也是不同。

六、修改默認對齊數

對,你沒有聽錯,默認對齊數是可以修改滴,當我們把默認對齊數修改為1時,結構體的成員變量就是連續(xù)存儲的。代碼如下,計算出來的大小就是4+1+8=13

#pragma pack(1)//修改默認對齊數為1
struct s
{
	int a;
	char b;
	double c;
};
#pragma pack()//修改默認對齊數為默認
int main()
{
	printf("%d\n", sizeof(struct s));
	return 0;
}

到此這篇關于詳解C語言如何計算結構體大小(結構體的內存對齊)的文章就介紹到這了,更多相關C語言計算結構體大小內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C語言中改變目錄的相關操作函數詳解

    C語言中改變目錄的相關操作函數詳解

    這篇文章主要介紹了C語言中改變目錄的相關操作函數詳解,分別是fchdir()函數和rewinddir()函數的使用方法,需要的朋友可以參考下
    2015-09-09
  • C語言數據結構之單鏈表存儲詳解

    C語言數據結構之單鏈表存儲詳解

    鏈表是一種物理存儲結構上非連續(xù)、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。本文將和大家一起聊聊C語言中單鏈表的存儲,感興趣的可以學習一下
    2022-07-07
  • 詳解C語言中return與exit的區(qū)別

    詳解C語言中return與exit的區(qū)別

    這篇文章主要介紹了詳解C語言中return與exit的區(qū)別的相關資料,希望通過本文能幫助到大家,讓大家理解這部分內容,需要的朋友可以參考下
    2017-10-10
  • C/C++ 中gcc和g++的對比與區(qū)別

    C/C++ 中gcc和g++的對比與區(qū)別

    這篇文章主要介紹了C/C++ 中gcc和g++的對比與區(qū)別的相關資料,需要的朋友可以參考下
    2017-07-07
  • 解析bitmap處理海量數據及其實現方法分析

    解析bitmap處理海量數據及其實現方法分析

    本篇文章是對bitmap處理海量數據及其實現的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C++ Boost Chrono實現計時碼表流程詳解

    C++ Boost Chrono實現計時碼表流程詳解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C語言實現類似wget的進度條效果

    C語言實現類似wget的進度條效果

    這篇文章主要介紹了C語言實現類似wget的進度條效果的方法,主要是讓大家可以熟練的使用轉移符\r,這里推薦給大家,需要的小伙伴參考下。
    2015-03-03
  • C語言實現隨機抽獎程序

    C語言實現隨機抽獎程序

    這篇文章主要為大家詳細介紹了C語言實現隨機抽獎程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C語言數據結構實例講解單鏈表的實現

    C語言數據結構實例講解單鏈表的實現

    單鏈表是后面要學的雙鏈表以及循環(huán)鏈表的基礎,要想繼續(xù)深入了解數據結構以及C++,我們就要奠定好這塊基石!接下來就和我一起學習吧
    2022-03-03
  • Qt實現拖動單個控件移動的示例代碼

    Qt實現拖動單個控件移動的示例代碼

    做慣了靜態(tài)圖,今天來搞一搞動態(tài)圖吧!本文將利用Qt實現拖動單個控件移動效果,文中的示例代碼講解詳細,感興趣的可以動手嘗試一下
    2022-06-06

最新評論