c语言中sizeof struct和sizeof union


一般32位机子上各个数据类型所占的存储空间如下:

char:8位 

short:16位

int:32位

long:32位

float:32位

double:64位

一、接下来先来看struct,结构体

请牢记以下3条原则:(在没有#pragma pack宏的情况下)

1、数据成员对齐规则:结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,之后的每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机子上为4字节,所以要从4的整数倍地址开始存储)。

2、结构体作为成员:如果一个结构体里同时包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(如struct a里有struct b,b里有char,int ,double等元素,那么b应该从8(即double类型的大小)的整数倍开始存储)。

3、结构体的总大小:即sizeof的结果。在按之前的对齐原则计算出来的大小的基础上,必须还得是其内部最大成员的整数倍,不足的要补齐(如struct里最大为double,现在计算得到的已经是11,则总大小为16)。

具体例子:

  1. typedef struct bb  
  2. {  
  3.     int id;             //[0]....[3]      表示4字节  
  4.     double weight;      //[8].....[15]      原则1  
  5.     float height;      //[16]..[19],总长要为8的整数倍,仅对齐之后总长为[0]~[19]为20,补齐[20]...[23]     原则3  
  6. }BB;  
<span style="font-size:18px;"><strong>typedef struct bb
{
	int id;             //[0]....[3]      表示4字节
	double weight;      //[8].....[15]      原则1
	float height;      //[16]..[19],总长要为8的整数倍,仅对齐之后总长为[0]~[19]为20,补齐[20]...[23]     原则3
}BB;</strong></span>
  1. typedef struct aa    
  2. {     
  3.     int  id;         //[0]...[3]          原则1    
  4.     double score;     //[8]....[15]        
  5.     short grade;    //[16],[17]            
  6.     BB b;             //[24]......[47]       原则2(因为BB内部最大成员为double,即8的整数倍开始存储)    
  7.     char name[2]; //[48][49]  
  8. }AA;   
<span style="font-size:18px;"><strong>typedef struct aa  
{  	
	int  id;         //[0]...[3]          原则1  
	double score;     //[8]....[15]      
	short grade;    //[16],[17]          
	BB b;             //[24]......[47]       原则2(因为BB内部最大成员为double,即8的整数倍开始存储)  
	char name[2]; //[48][49]
}AA; </strong></span>

  1. int main()  
  2. {  
  3.     cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;  
  4.     return 0;  
  5. }  
<span style="font-size:18px;"><strong>int main()
{
	cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;
	return 0;
}</strong></span>
输出结果为56 24

以上结果是在没有#pragma pack(n)宏的情况下,现在来讲讲关于#pragma pack(n)。

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。//n为1、2、4、8、16...

n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,即该变量所占用字节数的整数倍;第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。

所以在上面的代码前加一句#pragma pack(1),

则代码输出为bb:(0~3)+(4~11)+(12~15)=16;aa:(0~3)+(4~11)+(12~13)+(14~29)+(30~31)=32,也就是说,#pragma pack(1)就是没有对齐规则。

再考虑#pragma pack(4),bb:(0~3)+(4~11)+(12~15)=16;aa:(0~1)+(4~11)+(12~13)+(16~31)+(32~35)=36

二、union共用体(联合)

共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中元类型(如数组,取其类型的数据长度)最大的变量长度的整数倍,且要大于等于其最大成员所占的存储空间。
  1. union foo  
  2. {  
  3. char s[10];  
  4. int i;  
  5. }  
<span style="font-size:18px;"><strong>union foo
{
char s[10];
int i;
}</strong></span>
在这个union中,foo的内存空间的长度为12,是int型的3倍,而并不是数组的长度10。若把int改为double,则foo的内存空间为16,是double型的两倍。
  1. union   mm{    
  2.   char   a;//元长度1        1  
  3.   int   b[5];//元长度4     20  
  4.   double   c;//元长度8     8  
  5.   int   d[3];              12  
  6.   };    
<span style="font-size:18px;"><strong>union   mm{  
  char   a;//元长度1        1
  int   b[5];//元长度4     20
  double   c;//元长度8     8
  int   d[3];              12
  };  
</strong></span>
所以sizeof(mm)=8*3=24;
当在共用体中包含结构体时,如下:
  1. struct inner  
  2. {  
  3.    char      c1;  
  4.    double   d;  
  5.    char     c2;  
  6.   };  
  7.   
  8. union data4  
  9. {  
  10.      struct   inner t1;  
  11.       int           i;  
  12.       char        c;  
  13.     };  
<span style="font-size:18px;"><strong>struct inner
{
   char      c1;
   double   d;
   char     c2;
  };

union data4
{
     struct   inner t1;
      int           i;
      char        c;
    };
</strong></span>
由于data4共用体中有一个inner结构体,所以最大的基本数据类型为double,因此以8字节对齐。共用体的存储长度取决于t1,而t1长度为24,因此sizeof(uniondata4)的值为24.

当在结构体中包含共用体时,共用体在结构体里的对齐地址为共用体本身内部所对齐位数,如下:
  1. typedef union{  
  2.     long i;  
  3.     int k[5];  
  4.     char c;  
  5. }DATE;  
  6. struct data{  
  7.     int cat;  
  8.     char cc;  
  9.     DATE cow;  
  10.     char a[6];  
  11. };  
<span style="font-size:18px;"><strong>typedef union{
	long i;
	int k[5];
	char c;
}DATE;
struct data{
	int cat;
	char cc;
	DATE cow;
	char a[6];
};</strong></span>
sizeof(DATE)=20, 而在结构体中中是4+1+3(补齐4对齐)+20+6+2(补齐4对齐)=36;


三、两者的区别

1. 共用体和结构体都是由多个不同的数据类型成员组成, 但在任何同一时刻, 共用体只存放了一个被选中的成员, 而结构体的所有成员都存在。
2. 对于共用体的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构体的不同成员赋值是互不影响的。
### C语言 `sizeof` 操作符的含义与用法 #### 含义 `sizeof` 是 C 语言中的一个操作符,用于计算指定类型或对象在内存中占据的空间大小,其返回值的单位为字节。它是编译期常量表达式的一部分,因此不会在运行时消耗额外的时间资源[^2]。 #### 使用场景 1. **针对数据类型** 计算基础数据类型的大小可以直接通过 `sizeof(类型)` 的形式完成。例如: ```c printf("Size of int: %zu bytes\n", sizeof(int)); ``` 2. **针对变量** 对于已定义的变量,可以通过 `sizeof(变量)` 或者 `sizeof 变量` 来获取该变量所占的存储空间大小。需要注意的是,括号在这里是可选的,但如果省略括号,则仅适用于单个标识符的情况[^3]。 示例代码如下: ```c double num = 3.14; printf("Size of variable 'num': %zu bytes\n", sizeof(num)); ``` 3. **针对数组** 当应用于数组名称时,`sizeof` 返回的是整个数组占用的总字节数而非单一元素的尺寸。这有助于区分数组与其对应的指针表示之间的差异[^3]。 ```c float array[5]; printf("Total size of the array: %zu bytes\n", sizeof(array)); printf("Size per element: %zu bytes\n", sizeof(float)); ``` 4. **特殊注意事项** - 如果将数组作为实参传递给函数,在函数体内再调用 `sizeof` 测量此参数的话,得到的结果将是对应指针类型的宽度而不是原始数组的实际容量[^3]。 ```c void func(float arr[]) { printf("Inside function, size is treated as pointer: %zu bytes\n", sizeof(arr)); // Typically prints 4 or 8 depending on architecture. } int main() { float data[10]; func(data); return 0; } ``` - 结构体成员可能因对齐填充而使得整体大于各字段简单相加之[^1]。 #### 数据结果类型 由 `sizeof` 运算得出的数值属于无符号整型 (`size_t`) 类别,这是标准头文件 `<stddef.h>` 中定义的一种别名类型[^2]。 --- ### 示例程序展示多种情况下的应用实例 ```c #include <stdio.h> int main(void){ short sVar = 123; long lVar = 987654L; struct ExampleStruct{ char cField; double dField; }; union SampleUnion{ int iVar; float fVar; }; printf("Short Variable Size :%zu Bytes.\n", sizeof(sVar)); printf("Long Variable Size :%zu Bytes.\n", sizeof(lVar)); printf("\nStructure Members Alignment Impact:\n"); printf("Char Field :%zu Byte.\n", sizeof(((struct ExampleStruct*)NULL)->cField)); printf("Double Field :%zu Bytes.\n", sizeof(((struct ExampleStruct*)NULL)->dField)); printf("Entire Structure :%zu Bytes (includes padding).\n", sizeof(struct ExampleStruct)); printf("\nUnions Share Same Memory Space Among All Fields:\n"); printf("Integer Union Member:%zu Bytes.\n", sizeof(((union SampleUnion*)NULL)->iVar)); printf("Float Union Member :%zu Bytes.\n", sizeof(((union SampleUnion*)NULL)->fVar)); printf("Overall Union :%zu Bytes.\n", sizeof(union SampleUnion)); return 0; } ``` 以上展示了如何利用 `sizeof` 探索不同类型及其组合结构的具体表现特征。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值