如何计算对象或者类型所占的内存字节数

本文详细解析了 C/C++ 中 sizeof 运算符的使用方法及其计算规则,包括基本数据类型、指针类型、数组类型及结构体类型的 sizeof 计算,并通过示例说明了边界对齐的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结一下将sizeof用于各种类型对象或类型时其结果的算法。

1、认识sizeof

sizeof是C/C++中的一个operator,其作用就是返回一个对象或者类型所占的内存字节数(byte)。返回值是size_t,在头文件stddef.h中定义。

2、用法

sizeof的用法有一下3种:

(1)sizeof(object);//即sizeof(对象)

(2)sizeof(type_name);//即sizeof(类型名,如int,char...etc)

(3)sizeof object;//即sizeof 对象

例如:

  1. int i;  
  2. sizeof(i);  
  3. sizeof(int);  
  4. sizeof i;  
  5. sizeof int//error!!!  

【注】:

(1)实际上sizeof计算对象的大小也是转换成对象类型来计算的,that is to say:对同类型的不同对象使用sizeof操作,得到的值是一样的。

(2)关于上面第(1)个表达式中的object,其可以延伸至一个unary-expression(一元表达式),例如:

  1. sizeof(2); //相当于sizeof(int)   
  2. sizeof(2+4.55); //相当于sizeof(2.0+4.55),从而相当于sizeof(double)  

(3)sizeof可以对函数调用求值,就相当于对该函数的返回值类型求sizeof。

  1. char foo()  
  2. {  
  3.     cout<<"foo函数被调用!"<<endl;  
  4.     return 'a';  
  5. }//函数   
  6. int foo_size;  
  7. foo_size=sizeof(foo());//相当于求sizeof(char)  

(4)sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用。

例如:

  1. char ary[ sizeofint ) * 10 ];  //ok~~~  

3、各种sizeof计算

(1)基本数据类型的sizeof(C++primer中叫内置类型),如:int,char,double,float,short,long

在32位计算机中,各种内置类型所占的字节数如下:

char-------------1bytes;

short------------2bytes;

int----------------4bytes;

long--------------4bytes;

float--------------4bytes;

double-----------8bytes;

long double----8bytes;

(2)指针数据类型的sizeof

指针记录了另一个对象的地址,即指针变量是用来存放地址数据的,那么其当然等于计算机地址总线的宽度了。所以在32位计算机中,无论指针p指向何种类型的数据对象,其sizeof结果肯定为4bytes。

  1. char *pc="abcd";  
  2. int *pi;  
  3. string *ps;  
  4. char **ppc=&pc;  
  5. void (*ppf)();//函数指针   
  6. cout<<"sizeof(pc)="<<sizeof(pc)<<endl;  
  7. cout<<"sizeof(pi)="<<sizeof(pi)<<endl;  
  8. cout<<"sizeof(ps)="<<sizeof(ps)<<endl;  
  9. cout<<"sizeof(ppc)="<<sizeof(ppc)<<endl;  
  10. cout<<"sizeof(ppf)="<<sizeof(ppf)<<endl;//这5个结果均为4bytes  

(3)数组类型的sizeof

数组的sizeof值等于数组所占用的内存字节数。

【切记】:有人以为sizeof(数组名)是求数组中元素的个数,这种认识是严重错误的。
例如:

  1. char a1[]="abcd";  
  2. int a2[3];  
  3. sizeof(a1)=5*1=5bytes;//一个char类型占1byte   
  4. sizeof(a2)=3*4=12bytes;  

【注】:

(1)求数组元素的两种方法

  1. int counts_a1=sizeof(a1)/sizeof(char);  
  2. int counts_a1=sizeof(a1)/sizeof(a1[0]);  

(2)当数组名被用作函数参数传递时,此时的数组名变蜕化成一个相应类型的指针了

  1. void foo3(char a3[3])   
  2. {     
  3. int c3 = sizeof( a3 ); // c3 =3  这里c3=sizeof(a3),想当于c3=sizeof(char*),故c3=4!!!    
  4. }  
  5.   
  6. void foo4(char a4[])  
  7. {     
  8. int c4 = sizeof( a4 ); // 同上,c4 =4!!!     
  9. }  

(4)结构体的sizeof

结构体在内存中时如何实际存储的呢?

结构体的大小不是所有成员大小的简单的相加,还需要考虑一个很重要的问题---------系统在存储结构体变量时存在一个“边界对齐”的问题。其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。编译器会按照成员列表的顺序一个接一个地给每个成员分配内存的,字节对齐的细节遵循以下3个原则:

1)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);

2)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding);

下面用例子来说明VC是怎样存放结构体的。例如:

Eg1:

  1. //结构体1   
  2. struct Mystruct1  
  3. {  
  4. double data_db;  
  5. char data_ch;  
  6. int data_i;  
  7. };  

分析:

为上面的结构体分配内存的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员data_db分配内存,其起始地址跟结构的起始地址相同(即data_db的偏移量为0,刚好为sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员data_ch分配内存,这时下一个可以分配的地址相对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把data_ch存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(char)=1个字节;接下来为第三个成员type分配空间,这时下一个可以分配的地址相对于结构的起始地址的偏移量为9,不是sizeof(int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址相对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。

Eg2:

  1. //结构体2   
  2. struct Mystruct2  
  3. {  
  4. char data_ch;  
  5. double data_db;  
  6. int data_i;  
  7. };  

分析:

为上面的结构体分配内存的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员data_ch分配内存,其起始地址跟结构的起始地址相同(即data_ch的偏移量为0,刚好为sizeof(char)的倍数),该成员变量占用sizeof(char)=1个字节;接下来为第二个成员data_db分配内存,这时下一个可以分配的地址相对于结构的起始地址的偏移量为1,不是sizeof(double)=8的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充7个字节(这7个字节没有放什么东西),这是下一个可以分配的地址相对于结构的起始地址的偏移量变为8,是sizeof(double)=8的倍数了,所以把data_db存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(double)=8个字节。接下来为第三个成员data_i分配空间,这时下一个可以分配的地址相对于结构的起始地址的偏移量为16,是sizeof(int)=4的倍数,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:1+7+8+4=20,不是结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以还得在第三个成员变量data_i的后面填充4个字节,使其达到24个字节,成为字节边界数的倍数。所以整个结构的大小为:sizeof(MyStruct)=1+7+8+4+4=24,其中有7+4个字节是VC自动填充的,没有放任何有意义的东西。

Eg3:

  1. #include <iostream>   
  2. using namespace std;  
  3.   
  4. char foo()  
  5. {  
  6.     cout<<"foo函数被调用!"<<endl;  
  7.     return 'a';  
  8. }  
  9.   
  10. int main()  
  11. {  
  12.     //内置数据类型   
  13.     int a=5;  
  14.     char b='c';  
  15.     cout<<"内置数据类型:"<<endl;  
  16.     cout<<sizeof(int)<<endl;  
  17.     cout<<sizeof(a)<<endl;  
  18.     cout<<sizeof(char)<<endl;  
  19.     cout<<sizeof(b)<<endl;  
  20.   
  21.     //对指针求其大小   
  22.     cout<<"指针数据类型:"<<endl;  
  23.     char *pc="abcd";  
  24.     int *pi;  
  25.     string *ps;  
  26.     char **ppc=&pc;  
  27.     void (*ppf)();//函数指针   
  28.     cout<<"sizeof(pc)="<<sizeof(pc)<<endl;  
  29.     cout<<"sizeof(pi)="<<sizeof(pi)<<endl;  
  30.     cout<<"sizeof(ps)="<<sizeof(ps)<<endl;  
  31.     cout<<"sizeof(ppc)="<<sizeof(ppc)<<endl;  
  32.     cout<<"sizeof(ppf)="<<sizeof(ppf)<<endl;  
  33.   
  34.   
  35.     //对函数调用求值   
  36.     cout<<"函数调用:"<<endl;  
  37.     int foo_size;  
  38.     foo_size=sizeof(foo());  
  39.     cout<<"sizeof(foo())="<<foo_size<<endl;//函数foo()并不会被调用,sizeof对一个函数调用求值,就相当于对该函数的返回类型求sizeof, 即sizeof(char)   
  40.   
  41.   
  42.     //对结构体求值   
  43.     cout<<"对结构体类型:"<<endl;  
  44.     struct ALIGN1  
  45.     {  
  46.         char a;  
  47.         int b;  
  48.         char c;  
  49.     };  
  50.       
  51.   
  52.     //调整ALIGN1中成员列表   
  53.     struct ALIGN3  
  54.     {  
  55.         int b;  
  56.         char a;  
  57.         char c;  
  58.     };  
  59.   
  60.     struct ALIGN2  
  61.     {  
  62.         double a;  
  63.         char b;  
  64.         int c;  
  65.     };  
  66.   
  67.     //再举一个例子   
  68.     //结构体1   
  69.     struct Mystruct1  
  70.     {  
  71.         double data_db;  
  72.         char data_ch;  
  73.         int data_i;  
  74.   
  75.     };  
  76.     //结构体2   
  77.     struct Mystruct2  
  78.     {  
  79.         char data_ch;  
  80.         double data_db;  
  81.         int data_i;  
  82.     };  
  83.   
  84.   
  85.   
  86.     cout<<"struct1的大小:"<<endl;  
  87.     cout<<sizeof(ALIGN1)<<endl;  
  88.     cout<<"a的偏移量:"<<offsetof(ALIGN1,a)<<endl;  
  89.     cout<<"b的偏移量:"<<offsetof(ALIGN1,b)<<endl;  
  90.     cout<<"c的偏移量:"<<offsetof(ALIGN1,c)<<endl;  
  91.   
  92.     cout<<"struct2的大小:"<<endl;  
  93.     cout<<sizeof(ALIGN2)<<endl;  
  94.   
  95.   
  96.     cout<<"struct3的大小:"<<endl;  
  97.     cout<<sizeof(ALIGN3)<<endl;  
  98.     cout<<"a的偏移量:"<<offsetof(ALIGN3,a)<<endl;  
  99.     cout<<"b的偏移量:"<<offsetof(ALIGN3,b)<<endl;  
  100.     cout<<"c的偏移量:"<<offsetof(ALIGN3,c)<<endl;  
  101.   
  102.     //输出Mystruct1和Mystruct2的大小   
  103.     cout<<"sizeof(Mystruct1)="<<sizeof(Mystruct1)<<endl;  
  104.     cout<<"sizeof(Mystruct2)="<<sizeof(Mystruct2)<<endl;  
  105.   
  106.     //查看Mystruct1和Mystruct2中变量的(相对于结构体的起始地址)偏移量   
  107.     cout<<"Mystruct1_data_db的偏移量="<<offsetof(Mystruct1,data_db)<<endl;  
  108.     cout<<"Mystruct1_data_ch的偏移量="<<offsetof(Mystruct1,data_ch)<<endl;  
  109.     cout<<"Mystruct1_data_i的偏移量="<<offsetof(Mystruct1,data_i)<<endl;  
  110.   
  111.     cout<<"Mystruct2_data_db的偏移量="<<offsetof(Mystruct2,data_db)<<endl;  
  112.     cout<<"Mystruct2_data_ch的偏移量="<<offsetof(Mystruct2,data_ch)<<endl;  
  113.     cout<<"Mystruct2_data_i的偏移量="<<offsetof(Mystruct2,data_i)<<endl;  
  114.   
  115.   
  116.   
  117.     return 0;  
  118. }  
<think>好的,我现在要回答用户的问题:“C语言怎么判断数据类型字节数”。首先,我需要回想一下C语言中有关数据类型大小的知识。用户可能是在学习C语言的基础,或者在进行底层编程时需要知道不同数据类型存储需求。我需要确保我的回答准确且易于理解。 首先,我应该想到C语言中用来获取数据类型大小的运算符是sizeof。这个运算符可以返回类型或变量在内存中所字节数。例如,sizeof(int)会给出int类型字节数。不过,具体的大小可能因编译器和系统不同而有所变化,这一点需要特别指出,避免用户产生误解,认为所有环境下结果都一样。 接下来,我应该考虑如何实际使用sizeof。用户可能需要具体的例子,比如如何获取基本数据类型(如int、char、float、double)的大小,以及结构体或数组的大小。此外,用户可能想知道如何在程序中输出这些信息,因此需要用printf函数,并配合正确的格式说明符。这里需要注意,sizeof返回的是size_t类型,所以应该用%zu来格式化输出,否则可能会有警告或错误。 另外,用户可能对为什么不同环境下数据类型大小不同感兴趣。这时候需要简单解释一下,C语言标准只规定了最小范围,具体实现由编译器根据硬件和操作系统决定。比如,在32位和64位系统中,指针的大小可能不同,int可能是2字节或4字节等等。 然后,我需要组织这些信息,先介绍sizeof运算符,然后给出示例代码,再解释可能的结果差异原因。还需要提醒用户实际编程中应该使用sizeof而不是假设大小,以保证代码的可移植性。 可能用户还会有疑问,比如结构体的对齐问题是否会影响sizeof的结果。这时候虽然问题不直接相关,但可以简要提及结构体的大小可能因对齐而大于各成员之和,但如果不深入的话,可能暂时不需要展开。 最后,检查是否有错误或遗漏的地方。例如,是否提到了使用%zu格式符,是否解释了不同平台下的差异,是否给出了正确且完整的示例代码。确保回答清晰,步骤明确,适合不同层次的学习者理解。</think>在C语言中,可以使用 **`sizeof` 运算符**来判断数据类型或变量所字节数。`sizeof` 是编译时运算符,它会返回指定类型对象内存用的字节数。以下是具体方法: --- ### 1. **基本用法** ```c #include <stdio.h> int main() { printf("int %zu 字节\n", sizeof(int)); printf("char %zu 字节\n", sizeof(char)); printf("float %zu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值