C/C++ sizeof函数解析——解决sizeof求结构体大小的问题

时间:2021-08-14 02:09:48

C/C++中不同数据类型所占用的内存大小

32位                 64位

char               1                    1

int                  4             大多数4,少数8

short              2                    2

long               4                    8

float               4                    4

double            8                    8

指针                    4                         8

(单位都为字节)

结构体(struct):比较复杂,对齐问题。

联合(union):所有成员中最长的。

枚举(enum):根据数据类型。

sizeof计算单层结构体大小

  运算符sizeof可以计算出给定类型的大小,对于32位系统来说,sizeof(char) = 1; sizeof(int) = 4。基本数据类型的大小很好计算,我们来看一下如何计算构造数据类型的大小。

C语言中的构造数据类型有三种:数组、结构体和共用体。

 数组是相同类型的元素的集合,只要会计算单个元素的大小,整个数组所占空间等于基础元素大小乘上元素的个数

结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。和数组不一样的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。看下面这样的一个结构体:

struct stu1
{
int i;
char c;
int j;
};

用sizeof求该结构体的大小,发现值为12。int占4个字节,char占1个字节,结果应该是9个字节才对啊,为什么呢?

先介绍一个相关的概念——偏移量。偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。因此,第一个成员i的偏移量为0。第二个成员c的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;第三个成员j的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为5。

然而,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则

      (1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍) 

      (2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。

上面的例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为5,并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上3个空字节,使得第三个成员的偏移量变成8。结构体大小等于最后一个成员的偏移量加上其大小,上面的例子中计算出来的大小为12,满足要求。

再来看另外一个例子:

struct stu2
{
int k;
short t;
};

   成员k的偏移量为0;成员t的偏移量为4,都不需要调整。但计算出来的大小为6,显然不是成员k大小的整数倍。因此,编译器会在成员t后面补上2个字节,使得结构体的大小变成8从而满足第二个要求。

由此可见,结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小

对比下面两种定义顺序:

struct stu3
{
char c1;
int i;
char c2;
}
struct stu4
{
char c1;
char c2;
int i;
}

  虽然结构体stu3和stu4中成员都一样,但sizeof(struct stu3)的值为12而sizeof(struct stu4)的值为8。

sizeof计算嵌套的结构体大小

对于嵌套的结构体需要将其展开。对结构体求sizeof时,上述两种原则变为:

       (1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。

       (2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。

看下面的例子:

struct stu5
{
short i;
struct
{
char c;
int j;
} ss;
int k;
}

  结构体stu5的成员ss.c的偏移量应该是4,而不是2。整个结构体大小应该是16。

下述代码测试原则2:

struct stu5
{
char i;
struct
{
char c;
int j;
} ss;
char a;
char b;
char d;
char e;
char f;
}

  结构体ss单独计算占用空间为8,而stu5的sizeof则是20,不是8的整数倍,这说明在计算sizeof(stu5)时,将嵌套的结构体ss展开了,这样stu5中最大的成员为ss.j,占用4个字节,20为4的整数倍。如果将ss当做一个整体,结果应该是24了。

另一个特殊的例子是结构体中包含数组,其sizeof应当和处理嵌套结构体一样,将其展开,如下例子:

struct ss
{
float f;
char p;
int adf[];
};

  其值为20。float占4个字节,到char p时偏移量为4,p占一个字节,到int adf[3]时偏移量为5,扩展为int的整数倍,而非int adf[3]的整数倍,这样偏移量变为8,而不是12。结果是8+12=20,是最大成员float或int的大小的整数倍。

如何给结构体变量分配空间由编译器决定,以上情况针对的是Linux下的GCC。在Windows下的VC平台也是这样,至于其他平台,可能会有不同的处理。

  致谢:感谢您的耐心阅读!

C/C++ sizeof函数解析——解决sizeof求结构体大小的问题的更多相关文章

  1. sizeof进行结构体大小的判断

    typedef struct{    int a;    char b;}A_t;typedef struct{    int a;    char b;    char c;}B_t;typedef ...

  2. PHP json_decode 函数解析 json 结果为 NULL 的解决方法

    在做网站 CMS 模块时,对于模块内容 content 字段,保存的是 json 格式的字符串,所以在后台进行模块内容的编辑操作 ( 取出保存的数据 ) 时,需要用到 json_decode() 函数 ...

  3. C语言中的sizeof函数总结

    sizeof函数的结果: 变量:变量所占的字节数. ; printf( 数组:数组所占的字节数. ,,,,}; ] = {,,,,}; printf("size_arr1=%d\n&quot ...

  4. 函数strlen()和sizeof的区别

    函数strlen()和sizeof的区别: #include<stdio.h> #include<stdlib.h> #include<string.h> #def ...

  5. 数据类型、位运算、sizeof&lpar;&rpar;函数

    数据精度,依次升高.(负数必须使用有符号类型) 不同精度的数据间运算,所得结果为高精度类型. 数据类型详细信息如下图: 整型数据的数制:十进制(32).八进制(032,以0开头).十六进制(0x32, ...

  6. 含有虚函数的类sizeof大小

    #include <iostream> using namespace std; class Base1{ virtual void fun1(){} virtual void fun11 ...

  7. 数组名作为函数参数以及sizeof用法

    来源:https://blog.csdn.net/jay_zhouxl/article/details/51745518 int f(int *p,char *a) { printf("p[ ...

  8. C sizeof函数

    #include<stdio.h> int main() { struct stu { union { ]; ]; } cls; ]; float cj; } xc; printf(&qu ...

  9. PHP sizeof&lpar;&rpar; 函数

    实例 返回数组中元素的数目: <?php$cars=array("Volvo","BMW","Toyota");echo sizeof ...

随机推荐

  1. div赋值&comma;取值和input赋值,取值

    一.div取值 <div id="txtXiaofei" class="txt-panel">你好</div> 获取div的值$(&qu ...

  2. 计算NSString含有多少个相同字符串

    // //  NSString+NSStringExt.m //  01-NSString类 // //  Created by apple on 14-3-20. //  Copyright (c) ...

  3. Android 发送短信与接收短信

    package com.example.testsms; import android.app.Activity; import android.app.PendingIntent; import a ...

  4. phpcms二级菜单

    二级 {pc:content action="category" catid="0" siteid="$siteid" order=&quo ...

  5. Web&colon;&colon;Scraper 页面提取分析

    一组用来提取HTML文档中元素内容的工具集,它能够理解HTML和CSS选择器以及XPath表达式. 语法 use URI; use Web::Scraper; # First, create your ...

  6. Linux 部署 Tomcat和JDK

    一:安装jdk下载将jdk加压后放到/usr/local目录下: [root@master ~]#chmod 755 jdk-6u5-linux-x64.bin [root@master ~]# ./ ...

  7. Linux CentOS下MySQL的安装配置之浅谈

    前期必备安装:VMware虚拟机,CentOS镜像[注意:Linux下使用CentOS   MySQL是不用在官网下载的,只需要配置就OK了] 下面开始正式操作: //CentOS安装MySQL之浅谈 ...

  8. registry key &&num;39&semi;Java Runtime Environment&&num;39&semi; has value&&num;39&semi;1&period;8&&num;39&semi;&comma;but &&num;39&semi;1&period;7&&num;39&semi; is requaired(转)

    当更新jdk后,运行java命令可能会提示类似这样registry key 'Java Runtime Environment' has value'1.8',but '1.7' is requair ...

  9. python logging模块&plus; 个人总结

    原文地址:http://www.cnblogs.com/sislcb/archive/2008/11/25/1340627.html 从Python2.3版本中开始引入的logging模块为应用提供了 ...

  10. Linux&lpar;Centos&rpar;下调整分区大小(以home和根分区为例)

      在安装新系统的时候,有时候没法预估或者说错误的划分了分区大小,常常会导致我们后面的操作出现极大地不方便,比如某个分区分的太小了,导致 软件安装的时候会报安装空间不够,这就很麻烦.在这里我就记录一下 ...