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.mzph.cn/news/384437.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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;而后者是…

对象的浅拷贝和深拷贝

对象的浅拷贝和深拷贝简要介绍代码实现简要介绍 浅拷贝&#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;如何生成可参考右边的帮助文档 文章目录前言…

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脚本在唤醒…

Linux系统编程(二)孤儿进程和僵尸进程

Linux系统编程&#xff08;二&#xff09;一、exec函数族1.exec函数二、孤儿进程和僵尸进程三、wait和waitpid1.wait函数2.waitpid函数一、exec函数族 exec函数使用时&#xff0c;改程序的用户空间的代码和数据会被新程序给替代&#xff0c;会从新程序的启动例程开始。调用exe…

linux下c/c++实例之十socket简单应用

转自&#xff1a;http://blog.csdn.net/taiyang1987912/article/details/49738351 一、简介 通过socket扫描本机打开的tcp端口号&#xff0c;模拟用户名、密码登录服务器的过程、socket文件传输及模仿http服务器。 二、详解 1、Linux下tcp端口扫描 &#xff08;1&#xff09;…

Linux系统编程(三)进程间的通信

Linux系统编程&#xff08;三&#xff09;进程间的通信一、为什么需要进程之间的通信&#xff08;IPC&#xff09;&#xff1f;二、管道1.概念2.特质3.原理4.局限性5.代码2.读入数据三、共享存储映射注意事项父子进程通信一、为什么需要进程之间的通信&#xff08;IPC&#xff…

exec 函数族

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187409.html linux系统编程之进程&#xff08;五&#xff09;&#xff1a;exec系列函数&#xff08;execl,execlp,execle,execv,execvp)使用 本节目标&#xff1a; exec替换进程映像exec关联函数组&#xff08;execl、execl…

Linux系统编程(四)信号

Linux系统编程&#xff08;四&#xff09;信号一、什么是信号&#xff1f;1、信号的本质2、信号来源硬件来源软件来源二、常见信号1.可靠信号和不可靠信号2、不可靠信号主要有以下问题:3、可靠信号与不可靠信号注册机制三、信号处理方式四、信号处理过程五、未决信号和阻塞信号…

SIGCHLD信号回收子进程

SIGCHLD信号回收子进程代码问题注意点代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h>void handler(int signo) {int status; pid_t pid;while ((pid waitpid(0, &status…

Wait waitpid

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187770.html linux系统编程之进程&#xff08;六&#xff09;&#xff1a;父进程查询子进程的退出,wait,waitpid 本节目标&#xff1a; 僵进程SIGCHLDwaitwaitpid 一&#xff0c;僵尸进程 当一个子进程先于父进程结束运行时…

Linux C++ 简单爬虫

转载&#xff1a;http://blog.csdn.net/orthocenterchocolate/article/details/38665937 方便易用&#xff0c;传入URL&#xff0c;返回对应页面的内容 [cpp] view plaincopy #include <iostream> #include <string> #include <netdb.h> #include <…

Linux系统编程(七)消息队列

Linux系统编程&#xff08;七&#xff09;消息队列一、什么是消息队列二、消息队列内部原理三、实现消息队列的收发1.发送消息队列2.接收消息队列四、消息队列与命名管道的比较一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都…