常用C语言函数 - 对齐

#pragma pack(4)
INT16U *D[D_Number];
#pragma pack()

#pragma pack(n)

解释一:

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

  规则:

  1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

  2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

解释二:

n 字节的对齐方式 VC 对结构的存储的特殊处理确实提高 CPU 存储变量的速度,但是有时候也带来 了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。 VC 中提供了#pragma pack(n)来设定变量以 n 字节对齐方式。n 字节对齐就是说 变量存放的起始地址的偏移量有两种情况:

第一、如果 n 大于等于该变量所占用的字 节数,那么偏移量必须满足默认的对齐方式。

第二、如果 n 小于该变量的类型所占用 的字节数,那么偏移量为 n 的倍数,不用满足默认的对齐方式。结构的总大小也有个 约束条件,分下面两种情况:如果 n 大于所有成员变量类型所占用的字节数,那么结 构的总大小必须为占用空间最大的变量占用的空间数的倍数; 否则必须为 n 的倍数。

下面举例说明其用法。 #pragma pack(push) //保存对齐状态

#pragma pack(4)//设定为 4 字节对齐

struct test { char m1; double m4; int m3; }; #pragma pack(pop)//恢复对齐状态 以上结构体的大小为 16:

下面分析其存储情况,首先为 m1 分配空间,其偏移量 为 0,满足我们自己设定的对齐方式(4 字节对齐),m1 大小为 1 个字节。接着开始 为 m4 分配空间,这时其偏移量为 1,需要补足 3 个字节,这样使偏移量满足为 n=4 的倍数(因为 sizeof(double)大于 4),m4 占用 8 个字节。接着为 m3 分配空间,这时 其偏移量为 12,满足为 4 的倍数,m3 占用 4 个字节。这时已经为所有成员变量分配 了空间,共分配了 16 个字节,满足为 n 的倍数。如果把上面的#pragma pack(4)改为 #pragma pack(8),那么我们可以得到结构的大小为 24。

大家看了这些文字描述头也一定会发麻吧,我坚持读完后,然后自己编写了一个程序:

#pragma pack(4)

struct node{

int e;
  char f;
  short int a;
  char b;

};

struct node n;

printf("%d\n",sizeof(n));

我自己算的结果是16,结果实际结果是:

然后结构体内部数据成员变动一下位置:

#pragma pack(4)

struct node{

char f;
  int e;
  short int a;
  char b;};

struct node n;

printf("%d\n",sizeof(n));

将对齐位数强制定位2

#pragma pack(2)

struct node{

char f;
  int e;
  short int a;
  char b;};

struct node n;

printf("%d\n",sizeof(n));

将对齐位数强制定位1

#pragma pack(1)

struct node{

char f;
  int e;
  short int a;
  char b;};

struct node n;

printf("%d\n",sizeof(n));

看着输出结果和文字描述有点晕,下面简单说一下俺的判定规则吧:

其实之所以有内存字节对齐机制,就是为了最大限度的减少内存读取次数。我们知道CPU读取速度比内存读取速度快至少一个数量级,所以为了节省运算花费时间,只能以牺牲空间来换取时间了。

下面举例说明如何最大限度的减少读取次数。

#pragma pack(1)

struct node{

char f;  1
  int e;   4
  short int a;  2
  char b;  1

};

struct node n;

printf("%d\n",sizeof(n));

这里强制按照1字节进行对齐,可以理解成所有的内容都是按照1字节进行读取(暂且这样理解,因为这样可以很好的理解内存对其机制),其他所有的数据成员都是1字节的整数倍,所以也就不用进行内存对其,各个成员在内存中就按照实际顺序进行排列,结构体实际长度为8

#pragma pack(2)

struct node{

char f;
  int e;
  short int a;
  char b;};

struct node n;

printf("%d\n",sizeof(n));

这里强制按照2字节进行对齐。如果内存分布仍然是连续的话,那么int e就得三次才能读到CPU中,所以为了“讲究”int e的读取,所以在char f之后预留1BYTE,最后的char b也是如此,所以长度为10

#pragma pack(4)

struct node{

char f;
  int e;
  short int a;
  char b;};

struct node n;

printf("%d\n",sizeof(n));

这里强制按照4字节进行对齐。所以char f后要预留3BYTE,而short int a 和 char b可以一次读取到CPU(按照4字节读取),所以长度为12

如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对其

时间: 2024-11-03 21:08:06

常用C语言函数 - 对齐的相关文章

常用C语言函数 - sprintf()

#define PrgFileNameFormatEx "O%04ld.txt" sprintf(Temp,PrgFileNameFormatEx,(long)(data1->Pcode)) int sprintf( char *buffer, const char *format [, argument] ... ); 除了前两个参数类型固定外,后面可以接任意多个参数.而它的精华,显然就在第二个参数:格式化字符串上. printf和sprintf都使用格式化字符串来指定串的格式

【三支火把】---常用C语言控制台函数总结(持续更新)

写了这么久的C程序,每次看到输出的结果都是从上往下排列的黑白框,有没有感觉很无聊啊?今天再次总结一个常用的控制台函数,能够帮助你做好一个好看的界面. 1.设置光标位置代码如下: 1 int main(void) 2 { 3 int a = 5; 4 COORD pos = {10,10}; //定义光标坐标位置 5 HANDLE hout://定义一个句柄 6 hout = GetStdHandle(STD_OUTPUT_HANDLE); //获得输出设备的句柄 7 SetConsoleCurs

C语言函数可变参数列表

C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏va_start.va_arg.va_end: 可变函数参数定义方法: #include <stdarg.h> void func(int count,...){ va_list ap; int ix, tmp; va_start(ap, a); for(ix=0;ix < count; ++

Appium常用的API函数

原文地址:http://blog.sina.com.cn/s/blog_68f262210102vzf9.html 常用的API函数 获取信息类API (1)获取默认系统语言对应的Strings.xml文件内的数据. get_app_string() (2)查找某一个语言环境对应的字符串文件Strings.xml内数据. get_app_string(String language) (3)获取当前activity,比如(.ApiDemos) current_activity() App安装与卸

Mysql研究之MySQL常用内置函数完全解析

说明: 1)可以用在SELECT/UPDATE/DELETE中,及where,orderby,having中 2)在函数里将字段名作为参数,变量的值就是字段所对应的每一行的值. 3)在程序设计语言如C++中提供的函数,MySQL大部分也提供了,关于MySQL函数的完整信息,请参阅<MySQL参考手册> 一.字符串函数[比较常用,需要掌握] 1. concat(s1,s2,…,sn) #把传入的参数连接成一个字符串 selectconcat(‘abc’,’def’); selectconcat(

linux下C语言函数执行时间统计

转载:http://blog.csdn.net/linquidx/article/details/5916701#t5 写好程序,用gcc编译,带上-pg参数,然后运行以后分析gmon.out文件: 命令exp:   gprof ./test-main ./gmon.out >1.log  在1.log中会生成各函数运行情况. gprof 1.1 简介 gprof实际上只是一个用于读取profile结果文件的工具.gprof采用混合方法来收集程序的统计信息,他使用检测方法,在编译过程中在函数入口

ABAP - 日期格式转换 &amp; ABAP常用日期处理函数

ABAP - 日期格式转换 现在提供以下一些日期格式转换的函数: Below are several FMs which can be used to convert date format. 1. CONVERSION_EXIT_IDATE_OUTPUT INPUT:      20080203 OUTPUT:   03FEB2008 2. CONVERT_DATE_TO_EXTERNAL INPUT:      20080203 OUTPUT:   02/03/2008    "Accord

C语言函数手册学习

目录 1.字符测试函数 2.字符串操作函数 3.内存管理函数 4.日期与时间函数 5.数学函数 6.文件操作函数 7.进程管理函数 8.文件权限控制函数 9.信号处理函数 10.接口处理函数 11.环境变量函数 12.终端控制函数 总结:这次偶然间找到了C语言函数手册,看他分类分的很清楚,就花了几个小时学一下,具体的函数讲解可以点击链接查看,或者查找手册,常用的函数就是我知道已经碰到过的函数,或者是用过的函数. 1.字符测试函数 1.1 isxdigit() 1.2 isupper() 1.3i

MySQL学习笔记_7_MySQL常用内置函数

 MySQL常用内置函数 说明: 1)可以用在SELECT/UPDATE/DELETE中,及where,orderby,having中 2)在函数里将字段名作为参数,变量的值就是字段所对应的每一行的值. 3)在程序设计语言如C++中提供的函数,MySQL大部分也提供了,关于MySQL函数的完整信息,请参阅<MySQL参考手册> 一.字符串函数[比较常用,需要掌握] 1. concat(s1,s2,...,sn) #把传入的参数连接成一个字符串 selectconcat('abc','def