C语言结构体内存对齐

简介: C语言结构体内存对齐


一、结构体内存对齐问题

如下的info_s结构体类型,包含一个int型成员age, 一个char型成员gender, 一个int型成员id。

单从数据成员的大小进行分析,整个结构体的大小应为9字节。

#include <stdio.h>
typedef struct info_s {
  int age;
  char gender;
  int id;
}info_s; 
int main(){
  info_s info = {
    .age = 10 ,
    .gender = 0,
    .id = 555
  };
  printf("size: %d\r\n",sizeof(info));
  return 0;
}

实际运行结果,表明结构体的实际大小为12字节。

这样会带来如下的问题:

一段流式的内容,包含的是info_s类型的信息( 代码中的info_stream ), 直接通过强制类型转换的方式就无法正常解析。

#include <stdio.h>
typedef struct info_s {
  int age;
  char gender;
  int id;
}info_s; 
int main(){
  char info_stream[9] = {0};
  *((int *)info_stream) = 10;
  *((char *)(info_stream + sizeof(int))) = 1;
  *((int *)(info_stream + sizeof(int) + sizeof(char))) = 555;
  
  info_s * p_info = (info_s*)info_stream;
  
  printf("age: %d\r\ngender: %d\r\nid: %d\r\n",p_info->age,p_info->gender,p_info->id);
  
  return 0;
}

id字段的解析是不正常的。

二、查看结构体成员起始位置

利用宏offsetof可以查看成员的起始位置相较于结构体起始位置的偏移量。

包含在头文件<stddef.h>中。

#include <stdio.h>
#include <stddef.h>
typedef struct info_s {
  int age;
  char gender;
  int id;
}info_s; 
int main(){
  info_s info ;
  
  printf("age idx: %d\r\n",offsetof(info_s,age));       //第一个参数是结构体类型,第二个参数是成员
  printf("gender idx: %d\r\n",offsetof(info_s,gender)); //对struct info_s,进行了重命名,所以直接写info_s
  printf("id idx: %d\r\n",offsetof(struct info_s,id));  //没有重命名就写struct info_s
  
  return 0;
}

可以看到id成员是从相对于头部位置,地址为8的位置开始的。

三、设置内存对齐方式

通过#pragma pack(n)命令可以设置变量的内存对齐方式

#include <stdio.h>
#pragma pack(1)
typedef struct info_s {
  int age;
  char gender;
  int id;
}info_s; 
int main(){
  info_s info  = {
    .age = 10 ,
    .gender = 0,
    .id = 555
  } ;
  
  printf("size: %d\r\n",sizeof(info));
  
  return 0;
}

设置按照1字节对齐后,得到了结构体的大小为9个字节。

#include <stdio.h>
#pragma pack(1)
typedef struct info_s {
  int age;
  char gender;
  int id;
}info_s; 
int main(){
  char info_stream[9] = {0};
  *((int *)info_stream) = 10;
  *((char *)(info_stream + sizeof(int))) = 1;
  *((int *)(info_stream + sizeof(int) + sizeof(char))) = 555;
  
  info_s * p_info = (info_s*)info_stream;
  
  printf("age: %d\r\ngender: %d\r\nid: %d\r\n",p_info->age,p_info->gender,p_info->id);
  
  return 0;
}

数据解析也正确。

相关文章
|
2月前
|
存储 安全 C语言
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
96 10
|
2月前
|
小程序 C语言
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
55 10
|
2月前
|
存储 编译器 C语言
【C语言程序设计——选择结构程序设计】求一元二次方程的根(头歌实践教学平台习题)【合集】
本任务要求根据求根公式计算并输出一元二次方程的两个实根,精确到小数点后两位。若方程无实根,则输出提示信息。主要内容包括: - **任务描述**:使用求根公式计算一元二次方程的实根。 - **相关知识**:掌握 `sqrt()` 函数的基本使用方法,判断方程是否有实根。 - **编程要求**:根据输入的系数,计算并输出方程的根或提示无实根。 - **测试说明**:提供两组测试数据及预期输出,确保代码正确性。 - **通关代码**:包含完整的 C 语言代码示例,实现上述功能。 通过本任务,你将学会如何处理一元二次方程的求解问题,并熟悉 `sqrt()` 函数的使用。
40 5
|
2月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】按从小到大排序三个数(头歌实践教学平台习题)【合集】
本任务要求从键盘输入三个数,并按从小到大的顺序排序后输出。主要内容包括: - **任务描述**:实现三个数的排序并输出。 - **编程要求**:根据提示在编辑器中补充代码。 - **相关知识**: - 选择结构(if、if-else、switch) - 主要语句类型(条件语句) - 比较操作与交换操作 - **测试说明**:提供两组测试数据及预期输出。 - **通关代码**:完整代码示例。 - **测试结果**:展示测试通过的结果。 通过本任务,你将掌握基本的选择结构和排序算法的应用。祝你成功!
49 4
|
3月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
231 14
|
2月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】求阶跃函数的值(头歌实践教学平台习题)【合集】
本任务要求输入x的值,计算并输出特定阶跃函数的结果。主要内容包括: 1. **选择结构基本概念**:介绍if、if-else、switch语句。 2. **主要语句类型**:详细解释if、if-else、switch语句的使用方法。 3. **跃迁函数中变量的取值范围**:说明如何根据条件判断变量范围。 4. **计算阶跃函数的值**:通过示例展示如何根据给定条件计算函数值。 编程要求:在右侧编辑器Begin-End之间补充代码,实现阶跃函数的计算和输出。测试说明提供了多个输入及其预期输出,确保代码正确性。最后提供通关代码和测试结果,帮助理解整个过程。
45 0
|
2月前
|
存储 算法 安全
【C语言程序设计——选择结构程序设计】判断一个数是不是5和7的倍数(头歌实践教学平台习题)【合集】
本任务要求输入一个正整数,判断其是否同时是5和7的倍数,若是输出&quot;Yes&quot;,否则输出&quot;No&quot;。内容涵盖选择结构的基本概念、主要语句类型(if、if-else、switch)及条件判断逻辑,帮助理解编程中的分支执行与条件表达式。测试用例包括正数、负数及非倍数情况,确保代码逻辑严谨。通关代码示例如下: ```cpp #include &quot;stdio.h&quot; int main(){ int a; scanf(&quot;%d&quot;, &a); if (a &lt;= 0){ printf(&quo
72 0
|
2月前
|
编译器 C语言 C++
【C语言程序设计——选择结构程序设计】求输入的日期是该年的第几天(头歌实践教学平台习题)【合集】
本任务要求编写程序,根据用户输入的年月日(以空格或回车分隔),计算并输出该天是该年的第几天,需注意判断闰年。主要内容包括: 1. **任务描述**:实现从键盘输入年月日,计算该天是当年的第几天。 2. **相关知识**: - `switch` 结构的基本语法及使用注意事项。 - 判断闰年的条件:能被4整除但不能被100整除,或能被400整除的年份为闰年。 3. **编程要求**:根据提示补充代码,确保程序正确处理输入并输出结果。 4. **测试说 示例代码展示了如何使用 `switch` 语句和闰年判断逻辑来完成任务。通过此练习,掌握 `switch` 语句的应用及闰年判断方法。
49 0
|
3月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
230 10
|
4月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。