C语言再学习15——预处理(三)

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

在这里插入图片描述


1. #pragma pack

测试:

#include <stdio.h>

int main(void)
{
	struct tagTestStruct_T
	{
		char ch;	//1字节
		short sh;	//2字节
		char str;	//1字节
		int i;		//4字节
	};

	struct tagTestStruct_T st_TestStruct;

	printf("ch %p,sh %p,str %p,i %p \r\n",
		(unsigned int)(void *)&st_TestStruct.ch - (unsigned int)(void *)&st_TestStruct,
		(unsigned int)(void *)&st_TestStruct.sh - (unsigned int)(void *)&st_TestStruct, 
		(unsigned int)(void *)&st_TestStruct.str - (unsigned int)(void *)&st_TestStruct,
		(unsigned int)(void *)&st_TestStruct.i - (unsigned int)(void *)&st_TestStruct);

	system("pause");
	return 0;
}

输出:
在这里插入图片描述

2. 内存对齐

字(2字节),双字(4字节),和四字(8字节)在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被 4 整除的地址,和可以被 8 整除的地址。)无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于:为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

了提高 CPU 的存储速度,编译器对一些变量的起始地址做了“对齐”处理。在默认情况下,编译器规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式:

类型对齐方式
char偏移量必须为sizeof(char)即1的倍数
int偏移量必须为sizeof(int)即4的倍数
float偏移量必须为sizeof(float)即4的倍数
double偏移量必须为sizeof(double)即8的倍数
short偏移量必须为sizeof(short)即2的倍数

各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节编译器会自动填充。同时编译器为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。

注:

对齐方式:变量存放的起始地址相对于结构的起始地址的偏移量;

3. 对齐规则

每个平台都有自己默认的“对齐系数”,在 VS2013 上测试为 4 字节对齐。我们可以通过命令 #pragma pack(n) 对内存进行对齐。通过预编译命令#pragma pack(n),n = 1,2,4,8,16 来改变对齐系数。

有效对齐值:是 #pragma pack(n) 指定的长度 n 与结构体中的成员变量中比较小的。

eg:
#pragma pack(1) 指定一字节对齐,而结构体中也定义有一字节的变量,那么对齐单位就是一字节;同样地,如果 #pragma pack(2) 指定 2 字节对齐,而结构体中也定义没有一字节的变量,那么对齐单位就是 2 字节,若结构体中有一字节变量,还是以一字节对齐;

如下的测试:

#include <stdio.h>

#pragma pack(2)

int main(void)
{
	struct tagTestStruct_T
	{
		short sh;
		int i;
	};

	struct tagTestStruct_T st_TestStruct;

	printf("size is %d \r\n",sizeof(st_TestStruct));

	system("pause");
	return 0;
}

输出结果为 2 字节对齐:

在这里插入图片描述注:

使用指令 #pragma pack (n),设置编译器将按照 n 个字节对齐。
使用指令 #pragma pack (),编译器将取消自定义字节对齐方式。

4. 规则测试

定义如下结构体:

#include <stdio.h>

//#pragma pack(1)

int main(void)
{
	struct tagTestStruct_T
	{
		char ch;
		short sh;
		char str;
		int i;
	};

	struct tagTestStruct_T st_TestStruct;

	printf("size is %d \r\n",sizeof(st_TestStruct));

	system("pause");
	return 0;
}

4.1 采用默认对齐

测试程序先注释掉://#pragma pack(1)。输出结果为:
在这里插入图片描述内存边界从 4 的倍数开始,如下图:

在这里插入图片描述

4.2 设置 1 字节对齐

测试程序先注释掉:打开 #pragma pack(1)。输出结果为:

在这里插入图片描述
内存边界从 1 开始,如下图:

在这里插入图片描述


参考:

1.C/C++内存对齐详解
2.C语言内存对齐详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值