首页 > 其他分享 >C语言基础:结构体对齐规则与0字节数组

C语言基础:结构体对齐规则与0字节数组

时间:2023-02-01 21:34:31浏览次数:43  
标签:struct C语言 member 偏移 printf test 对齐 字节


C语言基础:结构体对齐规则与0字节数组


  • 不同的编译器和系统默认的对齐规则会有差异,这里我使用的win32的MinGW
  • C语言结构体一般是默认四字节对其的。

结构体对其规则

一般的,C语言结构体默认是以4字节对其方式,以此默认4字节为依据,结构体对其规则有以下三项:

  • 规则一:struct内的第一个成员在偏移地址0处,随后成员的偏移地址在其本身类型大小整数倍处
  • 规则二:struct的总大小为内部最大成员类型的整数倍
  • 规则三:当A结构内含有结构B时,B在A中的偏移地址为B结构内最大元素类型的大小的整数倍

示例1:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define debug_printf(value) printf(#value " ---==> %d\n", value)

#define struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))

typedef struct
{
uint8_t a; // 偏移地址0
uint32_t b; // 偏移地址4
uint8_t c; // 偏移地址8
uint8_t d; // 偏移地址9
}test_t;

int main()
{
int a = struct_member_offset(test_t, a);
int b = struct_member_offset(test_t, b);
int c = struct_member_offset(test_t, c);
int d = struct_member_offset(test_t, d);
debug_printf(sizeof(test_t));
debug_printf(a);
debug_printf(b);
debug_printf(c);
debug_printf(d);
return 0;
}

输出结果:

C语言基础:结构体对齐规则与0字节数组_c++


解析:

  • a为第一个成员在偏移地址0处
  • b成员类型为无符号整形占用四字节,根据规则一b要对齐到4字节地址处,所以偏移地址为4,相当于在a成员后面补齐了3字节,不过这补齐的3个字节没用到
  • c和d成员大小都为1字节,根据规则一要对齐到1字节,所以c偏移为9,d偏移为10
  • 四个成员目前所占用的空间加起来是10字节,但是!此时还没完!根据规则二结构体的总大小为结构内最大成员的整数倍,test_t这个结构内最大成员是b占用4字节,所以10字节还要补齐2字节去对齐4字节,所以sizeof(test_t)=12。

示例二:

现在将d成员改为uint64类型:

typedef struct
{
uint8_t a;
uint32_t b;
uint8_t c;
uint64_t d;
}test_t;

输出结果:

C语言基础:结构体对齐规则与0字节数组_C语言0字节数组_02

还是根据规则解析:

  • a在偏移地址0处
  • b在4处
  • c在8处
  • abc所占用的空间为9个字节,d为uint64类型占8个字节,所以要对齐到8字节处,也就是偏移地址16处,相当于c成员后补齐了7字节。
  • 目前四个成员所占用的空间为24字节,24是d类型的倍数大小,所以sizeof(test_t)=24

示例三:
现在将结构改为如下,多了一个数据

typedef struct
{
uint8_t a;
uint32_t b;
uint8_t c[3];
uint8_t d;
uint64_t e;
}test_t;

输出结果:

C语言基础:结构体对齐规则与0字节数组_C语言0字节数组_03


c成员为3字节,占用偏移地址8,9,10三个空间,所以总大小还是24。


示例四:
将结构改为如下,现在test_t结构内包含结构sub_t。

typedef struct
{
uint8_t sub_a;
uint32_t sub_b;
}sub_t;

typedef struct
{
uint8_t a;
uint32_t b;
sub_t c;
uint8_t d;
uint64_t e;
}test_t;

输出结果:

C语言基础:结构体对齐规则与0字节数组_C结构体对齐_04

解析:

  • 根据规则一和二解析sizeof(sub_t)=8字节
  • 根据规则三确定sub_t在test_t中的偏移地址肯定是4的整数倍处,所以c这个结构成员偏移地址为8
  • d偏移地址为17
  • e偏移地址为24
  • sizeof(test_t)=32

字节为0的数组与结构体

先看一下0字节数组的大小:

int main()
{
int array[0];
debug_printf(sizeof(array));
return 0;
}

输出结果:

sizeof(array) ---==> 0

说明0字节数据占用空间为0,那么看下面这个例子:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define debug_printf(value) printf(#value " ---==> %d\n", value)

#define struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))

typedef struct
{
uint8_t a;
uint32_t b;
uint8_t c;
uint64_t d[0];
}test_t;

int main()
{
int a = struct_member_offset(test_t, a);
int b = struct_member_offset(test_t, b);
int c = struct_member_offset(test_t, c);
int d = struct_member_offset(test_t, d);
debug_printf(sizeof(test_t));
debug_printf(a);
debug_printf(b);
debug_printf(c);
debug_printf(d);
return 0;
}

输出结果:

C语言基础:结构体对齐规则与0字节数组_C语言0字节数组_05


!!奇怪的问题出现了!!

但道理说d成员占用空间为0,sizeof(test_t)应该是12才对,但是sizeof(test_t)却是16!!

原因:d成员虽然占用空间为0,但是他是uint64类型的,结构体的总大小是按照内部最大成员进行对齐的!test_t对齐到了8字节,所以sizeof(test_t)的大小为16字节!


ends…


标签:struct,C语言,member,偏移,printf,test,对齐,字节
From: https://blog.51cto.com/u_15950551/6031869

相关文章

  • C语言&C++
    C语言和C++中都有结构的概念,但是在C语言中结构只有成员变量,而没成员方法,而在C++中结构中,它可以有自己的成员变量和成员函数。但是在C语言中结构的成员是公共的,不管什么人想......
  • 初识C语言1
    #include<stdio.h>//standardinputoutputintmain()//主函数程序的入口,有且仅有一个{printf("helloworld");//printfunction打印函数return0;}C语言中的变量类型:char......
  • C语言练习------打字游戏
    1打字游戏(1)随机函数A:srand((unsigned)time(NULL));以当前时间为准,设置随机种子。注意:此函数,在每次开始游戏后调用一次即可。B:ch=rand();注意:rand()函数,每调用一次,产生一......
  • C语言-printf函数
    转换字符参数类型;转换结果cchar;字符dint;有符号十进制整数i同上edouble;以指数形式输出单、双精度浮点数(小写e)E同上(大写E)fdo......
  • C语言中return和exit的区别
    转载自:http://jszx.cuit.edu.cn/NewsCont.asp?bm=00&type=888&id=20050 1.exit用于在程序运行的过程中随时结束、终止程序,exit的参数是返回给OS的。main函数结束时(使用r......
  • 判断大小端--C语言版
    首先,什么是大小端存储方式?大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的......
  • 嵌入式开发中一些少见的C语言用法
    使用STM32开发的朋友不知道是否有发现过这样的一些宏定义?如下:#ifdefined(__CC_ARM)#pragmaanon_unions#endif看到上面的语句一开始确实搞不懂为什么要写这些东西,通过上......
  • 字节二面:100Wqps短链系统,如何设计?
    文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面......
  • 重学C语言
    /*Add(intx,inty)//自定义加法函数Add{//函数内容\函数体intz=x+y;returnz;}intmain(){intnum1=10;intnum2=20;intsum=0;inta=100;in......
  • C语言#初识C语言(一)
    自学C语言的第1天。1、什么是C语言2、第一个C程序3、数据类型和格式字符4、变量、常量1、什么是C语言 C语言是一种高级语言,在1972年由丹尼斯·里奇和肯·汤姆逊在开发UNIX......