sizeof()計算結構體的大小

原文鏈接:sizeof()計算結構體的大小_海月汐辰-CSDN博客_結構體的sizeof怎么計算

簡要說明:結構體成員按照定義時的順序依次存儲在連續的內存空間,但是結構體的大小并不是簡單的把所有成員大小相加,而是遵循一定的規則,需要考慮到系統在存儲結構體變量時的地址對齊問題。

一、沒有成員的結構體占用的空間是多少個字節?

? ? ?答案是:1個字節。

? ? ?這就是實例化的原因(空類同樣可以被實例化),每個實例在內存中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類或空結構體(C++中結構體也可看為類)隱含的加一個字節,這樣空類或空結構體在實例化后在內存得到了獨一無二的地址,所以空類所占的內存大小是1個字節。

二、首先介紹一個相關的概念——偏移量

? ? ? ? ? struct stru?
? ? ? ? ?{ ?
? ? ? ? ? ? ? ? ? ? int a; ?//start address is 0
? ? ? ? ? ? ? ? ? ?char b; ?//start address is 4
? ? ? ? ? ? ? ? ? ?int c; ?//start address is 8
? ? ? ? ?};

? ? ? ? ?偏移量指的是結構體變量中成員的地址和結構體變量地址的差。結構體大小等于最后一個成員的偏移量加上最后一個成員的大小。顯然,結構體變量中第一個成員的地址就是結構體變量的首地址。比如上面的結構體,第一個成員a的偏移量為0。第二個成員b的偏移量是第一個成員的偏移量加上第一個成員的大小(0+4),其值為4;第三個成員c的偏移量是第二個成員的偏移量應該是加上第二個成員的大小(4+1)。


三、在實際中,存儲變量時地址要求對齊,編譯器在編譯程序時會遵循兩條原則:

? ? ? ? ? ? ?(1)結構體變量中成員的偏移量必須是成員大小的整數倍(0被認為是任何數的整數倍)?

? ? ?(2)結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。

例子1:
struct stru1 ?
{ ?
? ? ?int a; ?//start address is 0
? ? ?char b; ?//start address is 4
? ? ?int c; ?//start address is 8
};

PS:用sizeof求該結構體的大小,發現值為12。int占4個字節,char占1個字節,結果應該是9個字節才對啊,為什么呢?這個例子中前兩個成員的偏移量都滿足要求,但第三個成員的偏移量為5,并不是自身(int)大小的整數倍。編譯器在處理時會在第二個成員后面補上3個空字節,使得第三個成員的偏移量變成8。結構體大小等于最后一個成員的偏移量加上其大小,上面的例子中計算出來的大小為12,滿足要求。

例子2:

struct stru2 ?
{ ?
? ? ? int i; ?//start address is 0
? ? ? short m; ?//start address is 4
};

PS:成員i的偏移量為0;成員m的偏移量為4,都不需要調整。但計算出來的大小為6,顯然不是成員m大小的整數倍。因此,編譯器會在成員m后面補上2個字節,使得結構體的大小變成8從而滿足第二個要求。

例子3、4:

?struct stru3 ?
{ ??
? ? ? ?char i; ?//start address is 0?
? ? ? ?int m; ? //start address is 4
? ? ? ?char n; ?//start address is 8
}; ?
struct stru4 ?
{ ?
? ? ? ?char i; ?//start address is 0
? ? ? ?char n; ?//start address is 1
? ? ? ?int m; ?//start address is 4
?};?

雖然結構體stru3和stru4中成員都一樣,但sizeof(struct stru3)的值為12而sizeof(struct stru4)的值為8。

由此可見,結構體類型需要考慮到字節對齊的情況,不同的順序會影響結構體的大小。

四、 對于嵌套的結構體,需要將其展開。對結構體求sizeof時,上述兩種原則變為:
? ? ? ?(1)展開后的結構體的第一個成員的偏移量應當是被展開的結構體中最大的成員的整數倍。

? ? ? ?(2)結構體大小必須是所有成員大小的整數倍,這里所有成員計算的是展開后的成員,而不是將嵌套的結構體當做一個整體。

例子1:

struct stru5 ?
{ ?
? ? ? short i; ?
? ? ? struct ??
? ? ? { ?
? ? ? ? ? ?char c; ?
? ? ? ? ? ?int j; ?
? ? ? } tt; ??
? ? ? int k; ?
};

結構體stru5的成員tt.c的偏移量應該是4,而不是2。整個結構體大小應該是16。

例子2:

struct stru6 ?
{ ?
? ? ? char i; ?
? ? ? struct ??
? ? ? { ?
? ? ? ? ? ?char c; ?
? ? ? ? ? ?int j; ?
? ? ? } tt; ??
? ? ? char a; ?
? ? ? char b; ?
? ? ? char d; ?
? ? ? char e; ?
? ? ? int f; ?
};

結構體tt單獨計算占用空間為8,而stru6的sizeof則是20,不是8的整數倍,這說明在計算sizeof(stru6)時,將嵌套的結構體ss展開了,這樣stu6中最大的成員為tt.j,占用4個字節,20為4的整數倍。如果將tt當做一個整體,結果應該是24了。

五:另一個特殊的例子是結構體中包含數組,其sizeof應當和處理嵌套結構體一樣,將其展開,如下例子:

struct array ?
{ ?
? ? float f; ?
? ? char p; ?
? ? int ?arr[3]; ?
};

其值為20。float占4個字節,到char p時偏移量為4,p占一個字節,到int arr[3]時偏移量為5,擴展為int的整數倍,而非int arr[3]的整數倍,這樣偏移量變為8,而不是12。結果是8+12=20,是最大成員float或int的大小的整數倍。

測試環境:vc++6.0

測試代碼:
?

//#ifndef __cplusplus//#endif#include <iostream>
#include "stdio.h"
#include <stdlib.h>
using namespace std;struct stru_empty
{};
struct stru1  
{  int a;  //start address is 0char b;  //start address is 4int c;  //start address is 8
};
struct stru2  
{  int i;  //start address is 0short m;  //start address is 4
};
struct stru3  
{   char i;  //start address is 0 int m;   //start address is 4char n;  //start address is 8
};  
struct stru4  
{  char i;  //start address is 0char n;  //start address is 1int m;  //start address is 4};struct stru5  
{  short i;  struct   {  char c;  int j;  } ss;   int k;  
};
struct stru6  
{  char i;  struct   {  char c;  int j;  } tt;   char a;  char b;  char d;  char e;  int f;  
};
struct stru7  
{  char i;  struct   {  char c;  //int j;  } tt;   char a;  char b;  char d;  char e;  int f;  
};
struct array  
{  float f;  char p;  int  arr[3];  
};
int main()
{ struct	stru6 st6;struct	stru7 st7;struct array ar;printf("sizof(char)=%d \n",sizeof(char));printf("sizof(int)=%d \n",sizeof(int));printf("sizof(short int)=%d \n",sizeof(short int));printf("sizof(long int)=%d \n",sizeof(long int));printf("sizof(long)=%d \n",sizeof(long));printf("sizof(float)=%d \n\n",sizeof(float));printf("sizof(stru_empty)=%d \n",sizeof(stru_empty));printf("sizof(stru1)=%d \n\n",sizeof(stru1));printf("sizof(stru2)=%d \n\n",sizeof(stru2));printf("sizof(stru3)=%d \n\n",sizeof(stru3));printf("sizof(stru4)=%d \n\n",sizeof(stru4));printf("sizof(stru5)=%d \n\n",sizeof(stru5));printf("sizof(stru6)=%d \n",sizeof(stru6)); printf("sizof(stru6.tt)=%d \n",sizeof(st6.tt));printf("the address of stru6.i=%d \n",&st6.i);printf("the address of stru6.a=%d \n\n",&st6.a);printf("sizof(stru7)=%d \n",sizeof(stru7));printf("sizof(stru7)=%d \n",sizeof(st7.tt));printf("the address of stru7.i=%d \n",&st7.i);printf("the address of stru7.a=%d \n\n",&st7.a);printf("sizof(ar)=%d \n",sizeof(ar));printf("sizof(ar.f)=%d \n",sizeof(ar.f));printf("sizof(ar.arr)=%d \n",sizeof(ar.arr));return 0;
}

運行結果:

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384437.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384437.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384437.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Shell export命令

Shell&#xff1a;export命令 - 百度文庫

Linux select 實現并發服務器和客戶端

轉載&#xff1a;http://blog.csdn.net/szkbsgy/article/details/10558881 [cpp] view plaincopy <span style"font-size:18px;">服務端&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys…

總線/通信筆記3 —— PDO與SDO的區別

PDO&#xff1a;過程數據對象&#xff08;Process Data Object&#xff09;&#xff0c;過程數據的發送&#xff0c;實時、速度快&#xff0c;提供對設備應用對象的直接訪問通道&#xff0c;它用來傳輸實時短幀數據&#xff0c;具有較高的優先權。PDO 傳輸的數據必須少于或等于…

gdb 根據函數地址 找 對應的函數名

debug時候&#xff0c;經常需要查找函數地址&#xff0c;在gdb中可以用 "info address function_name" (gdb) info address test Symbol "test" is a function at address 0x9e250 有時候&#xff0c;也會有知道函數地址&#xff0c;反找函數名的需求&am…

select、poll、epoll使用小結

轉載&#xff1a;http://blog.csdn.net/kkxgx/article/details/7717125 Linux上可以使用不同的I/O模型&#xff0c;我們可以通過下圖了解常用的I/O模型&#xff1a;同步和異步模型&#xff0c;以及阻塞和非阻塞模型&#xff0c;本文主要分析其中的異步阻塞模型。 一、select使用…

Qt報錯:undefined reference to xxxxx

報錯信息&#xff1a; 首先&#xff0c;要區分與undefined reference to xxxxx和 "xxxx was not declared in this scope"兩種報錯信息的差別&#xff0c;前者是因為編譯器能找到函數的聲明&#xff0c;但是找不到函數的定義&#xff0c;從而報錯&#xff1b;而后者是…

inet_pton, inet_ntop

轉自&#xff1a;http://www.cnblogs.com/s7vens/archive/2011/12/12/2284964.html Linux下這2個IP地址轉換函數&#xff0c;可以在將IP地址在“點分十進制”和“整數”之間轉換 而且&#xff0c;inet_pton和inet_ntop這2個函數能夠處理ipv4和ipv6。算是比較新的函數了。inet…

htonl(), ntohl(), htons(), ntohs() 函數

轉自&#xff1a;http://www.cnblogs.com/s7vens/archive/2011/12/12/2284892.html 在C/C寫網絡程序的時候&#xff0c;往往會遇到字節的網絡順序和主機順序的問題。這是就可能用到htons(), ntohl(), ntohs()&#xff0c;htons()這4個函數。 網絡字節順序與本地字節順序之間的…

inet_ntoa、 inet_aton、inet_addr

轉自&#xff1a;http://blog.csdn.net/zhangboyj/article/details/6157263 inet_addr() 簡述&#xff1a;將一個點間隔地址轉換成一個in_addr。 #include <winsock.h> unsigned long PASCAL FAR inet_addr( const struct FAR* cp); cp&#xff1a;一個以Internet標準“.…

對象的淺拷貝和深拷貝

對象的淺拷貝和深拷貝簡要介紹代碼實現簡要介紹 淺拷貝&#xff1a;python拷貝一般都是淺拷貝。拷貝時&#xff0c;對象包含的子對象內容不拷貝。因此&#xff0c;源對象和拷貝對象引用同一個對象 深拷貝&#xff1a;使用copy模塊的deepcopy函數&#xff0c;遞歸拷貝對象中包含…

用模板寫單鏈表

轉載自&#xff1a;http://blog.csdn.net/itcastcpp/article/details/39081953 為了加深對模板的理解&#xff0c;我們今天一起用模板寫一個單鏈表&#xff0c;希望通過這個例子&#xff0c;能夠幫助大家加深對模板的體會&#xff0c;具體如下&#xff1a; SList.hpp內容&#…

QT事件事件之一:Qt中的事件處理與傳遞

QT事件事件之一&#xff1a;Qt中的事件處理與傳遞前言一、簡介二、QT中的事件三、事件的實現的方法前言 在QT中&#xff0c;事件是我們很常用的東西&#xff0c;以下是我用事件時總結和做法 一、簡介 在QT中&#xff0c;事件作為一個對象&#xff0c;繼承QEvent類&#xff0c…

linux下成功安裝ffmpeg( 親測有效 )

linux下成功安裝ffmpeg&#xff08; 親測有效 &#xff09;一、下載二、安裝步驟1.安裝yasm2.安裝ffmpeg總結一、下載 ffmpeg 官網下載&#xff1a; http://ffmpeg.org/download.html 安裝yasm 官網下載&#xff1a;http://yasm.tortall.net/Download.html 二、安裝步驟 1.…

C++實現 簡單 單鏈表

轉自&#xff1a; http://blog.csdn.net/wonggonghong/article/details/21527577 我們首先建立一個<List.h>頭文件&#xff0c;聲明一個單鏈表結構&#xff1a; #include "List.h" [cpp] view plaincopy //創建一個單鏈表結構&#xff0c;包含一些常見的操作 …

ffmpeg音視頻基礎知識

ffmpeg音視頻基礎知識前言一、圖像的基礎知識二、視頻編碼基礎知識1.視頻和圖片之間的關系2.為什么要編碼&#xff1f;3.什么是編碼&#xff1f;視頻相關專業術語提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄前言…

數據結構之單鏈表——C++模板類實現

轉自&#xff1a;http://blog.csdn.net/Mrx_Nh/article/details/60471647 單鏈表定義 [cpp] view plaincopy #ifndef SinglyLinkedListEDLIST_H_INCLUDED #define SinglyLinkedListEDLIST_H_INCLUDED #include <bits/stdc.h> using namespace std; template&l…

Linux系統編程(一)

Linux系統編程&#xff08;一&#xff09;一、進程和程序二、內存布局內核空間用戶空間三、進程狀態四、環境變量五、進程共享一、進程和程序 程序&#xff1a;是指編譯好的二進制文件&#xff0c;存儲在磁盤中&#xff0c;不占用系統資源。 進程&#xff1a;是系統進行資源分…

Linux的SOCKET編程 簡單演示

轉載&#xff1a;http://blog.csdn.net/hguisu/article/details/7445768/ Linux的SOCKET編程詳解 1. 網絡中進程之間如何通信 進 程通信的概念最初來源于單機系統。由于每個進程都在自己的地址范圍內運行&#xff0c;為保證兩個相互通信的進 程之間既互不干擾又協調一致工作&a…

Unity(一)必然事件

【MonoBehaviour 類】&#xff08;一&#xff09;必然事件一、必然事件是什么&#xff1f;二、常用函數執行順序1.Awake2.Start3.update4.FixedUpdate三、Awake和start區別一、必然事件是什么&#xff1f; 在Unity中必然事件也稱腳本生命周期&#xff0c;是指在Unity腳本在喚醒…

正則匹配函數

轉載&#xff1a;http://blog.csdn.net/ithomer/article/details/6130806 1.int regcomp(regex_t *compiled, const char *pattern, int cflags) 這個函數把指定的規則表達式pattern編譯成一種特定的數據格式compiled&#xff0c;這樣可以使匹配更有效。函數regexec會使用這個數…