_pragma pack(n) 对齐用法详解
- 格式:doc
- 大小:145.00 KB
- 文档页数:2
C语言的字节对齐及#pragmapack的使用C编译器的缺省字节对齐方式(自然对界)在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。
各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。
C编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。
如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。
若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。
C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。
若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。
例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件):struct Test{char x1; // 成员x1为char型(其起始地址必须1字节对界),其偏移地址为0char x2; // 成员x2为char型(其起始地址必须1字节对界,其偏移地址为1float x3; // 成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4char x4; // 成员x4为char型(其起始地址必须1字节对界),其偏移地址为8};因为T est结构体中,最大的成员为flaot x3,因些此结构体的自然对界条件为4字节对齐。
则结构体长度就为12字节,内存布局为1100 1111 1000。
例子2:#include <stdio.h>//#pragma pack(2)typedef struct{int aa1; //4个字节对齐 1111char bb1;//1个字节对齐 1short cc1;//2个字节对齐 011char dd1; //1个字节对齐 1} testlength1;int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12typedef struct{char bb2;//1个字节对齐 1int aa2; //4个字节对齐 01111short cc2;//2个字节对齐 11char dd2; //1个字节对齐 1} testlength2;int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011 1111 1000,length = 12typedef struct{char bb3; //1个字节对齐 1char dd3; //1个字节对齐 1int aa3; //4个字节对齐 001111short cc23//2个字节对齐 11} testlength3;int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12typedef struct{char bb4; //1个字节对齐 1char dd4; //1个字节对齐 1short cc4;//2个字节对齐 11int aa4; //4个字节对齐 1111} testlength4;int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8int main(void){printf("length1 = %d.\n",length1);printf("length2 = %d.\n",length2);printf("length3 = %d.\n",length3);printf("length4 = %d.\n",length4);return0;}改变缺省的对界条件(指定对界)· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
C语言结构体中的数组字节对齐在C语言中,结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起。
结构体中常常包含多个成员变量,其中可能有数组类型的成员变量。
在结构体中使用数组时,需要了解数组字节对齐的概念和规则,以确保内存的最佳利用和访问的效率。
什么是字节对齐字节对齐是指在将数据存储在计算机内存中时,按照特定规则进行调整,以确保数据的存储和访问的效率。
字节对齐的规则可以对齐数据的起始地址或者数据的长度。
计算机中的数据存储是按照字节(Byte)来划分的,一个字节通常由8个二进制位组成。
字节对齐的主要目的是为了节省内存和提高访问效率。
在C语言中,结构体中的成员变量通常按照字节对齐的规则来排列。
C语言结构体中的数组字节对齐规则在C语言中,结构体中的数组字节对齐规则通常遵循以下原则:1.结构体的起始地址必须是所有成员变量所要求对齐方式的最小公倍数。
2.结构体中的每个成员变量的地址必须是它本身的大小的整数倍。
3.结构体的总大小必须是其最大成员变量大小的整数倍。
根据字节对齐规则,如果结构体中的成员变量的累计大小不是字节对齐的倍数,编译器会在成员变量之间添加填充字节,以满足对齐要求。
这些填充字节在结构体的占用空间中不可访问。
填充字节的目的是将后续成员变量的地址对齐,以提高内存访问效率。
数组字节对齐的示例为了更好地理解数组字节对齐的规则,我们来看一个示例。
#include <stdio.h>struct MyStruct {char c;int i;char arr[3];};int main() {struct MyStruct s;printf("sizeof(MyStruct) = %lu\n", sizeof(struct MyStruct));printf("sizeof(s.c) = %lu\n", sizeof(s.c));printf("sizeof(s.i) = %lu\n", sizeof(s.i));printf("sizeof(s.arr) = %lu\n", sizeof(s.arr));return 0;}输出结果:sizeof(MyStruct) = 12sizeof(s.c) = 1sizeof(s.i) = 4sizeof(s.arr) = 3在这个示例中,我们定义了一个包含一个字符类型变量、一个整型变量和一个长度为3的字符数组的结构体MyStruct。
#pragma pack(4) //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐typedef struct{char buf[3];//buf[1]按1字节对齐,buf[2]按1字节对齐,由于buf[3]的下一成员word a是按两字节对齐,因此buf[3]按1字节对齐后,后面只需补一空字节word a; //#pragma pack(4),取小值为2,按2字节对齐。
}kk;#pragma pack() //取消自定义字节对齐方式对齐的原则是min(sizeof(word ),4)=2,因此是2字节对齐,而不是我们认为的4字节对齐。
这里有三点很重要:1.每个成员分别按自己的方式对齐,并能最小化长度2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度3.对齐后的结构体整体长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐补充一下,对于数组,比如:char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐.如果写: typedef char Array3[3];Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度.不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个.声明:整理自网络达人们的帖子,部分参照MSDN。
作用:指定结构体、联合以及类成员的packing alignment;语法:#pragma pack( [show] | [push | pop] [, identifier], n )说明:1,pack提供数据声明级别的控制,对定义不起作用;2,调用pack时不指定参数,n将被设成默认值;3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;语法具体分析:1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment 数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop 直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack 中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。
pragma pack用法详解`#pragma pack` 是一个用于编译器的预处理指令,它用来调整内存对齐方式。
在C 和C++ 编程中,结构体和类的成员在内存中的存储是有对齐规则的,以提高访问效率。
`#pragma pack` 允许程序员更改默认的对齐规则。
在使用`#pragma pack` 时,你可以指定一个数值,表示对齐方式的字节数。
常见的使用方式如下:```cpp#pragma pack(n)```其中,`n` 表示所需的对齐字节数,通常是1、2、4、8等。
这个指令告诉编译器使用`n` 字节对齐。
以下是一个使用`#pragma pack` 的简单示例:```cpp#pragma pack(1) // 设置对齐为1字节struct ExampleStruct {char a; // 1字节int b; // 4字节short c; // 2字节};#pragma pack() // 恢复默认对齐方式```在上面的例子中,结构体`ExampleStruct` 的默认对齐方式可能是根据平台和编译器的不同而有所不同。
通过使用`#pragma pack(1)`,我们显式地将对齐方式设置为1字节,这样结构体中的每个成员都按照1字节对齐。
这可能会减小结构体在内存中的总大小,但也可能降低访问效率,因为对齐是为了提高读取内存的速度。
需要注意的是,`#pragma pack` 的使用可能会因编译器而异,因此在实际使用中应该注意跨平台兼容性。
在一些情况下,为了确保兼容性,可以使用其他手段来控制对齐方式,比如使用编译器提供的命令行选项或者特定的编译器指令。
C++中的结构体(struct)内存对齐是由编译器处理的,它的目的是为了提高访问结构体成员的效率,避免因内存对齐不当而导致的性能损失。
结构体内存对齐规则如下:
1.成员对齐规则:
–结构体的每个成员都有自己的对齐要求,要求的字节数是成员自身大小和默认对齐字节数中较小的那个。
默认对齐字节数通常是编译器或
平台相关的。
2.结构体整体对齐规则:
–结构体的整体对齐要求是结构体中所有成员对齐要求的最大值。
这确保结构体的起始地址和结尾地址都符合成员的对齐要求。
3.填充字节:
–为了满足对齐要求,编译器可能会在结构体的成员之间插入一些填充字节。
这些填充字节不属于结构体的成员,只是为了对齐而存在。
4.#pragma pack 指令:
–有时候,程序员可能需要更精确地控制结构体的对齐规则。
在这种情况下,可以使用#pragma pack指令来设置结构体的对齐字节数。
但要
注意,这样做可能影响性能,因为它可能导致额外的内存访问成本。
示例:
在这个例子中,ExampleStruct的大小是 16 字节,其中包含了填充字节以确保对齐。
实际的大小可能会因编译器和平台而异。
请注意,结构体内存对齐规则是平台和编译器相关的,不同的编译器和平台可能有不同的默认对齐策略。
如果你需要确切控制结构体的对齐,可以使用编译器提供的特定指令或选项。
结构体字节对齐的方法全文共四篇示例,供读者参考第一篇示例:结构体字节对齐是编程中一个非常重要的概念,尤其在涉及到内存对齐的底层编程中更是不可或缺。
在结构体的定义中,每个元素都需要在内存中占用一定的空间,而结构体整体的大小受到字节对齐规则的限制。
本文将介绍结构体字节对齐的方法及其原理,希望能帮助读者更好地理解和掌握这一概念。
一、什么是字节对齐字节对齐是指在结构体中每个元素按照特定的规则分配内存空间,以便提高内存读取的效率。
在计算机系统中,一般要求数据在内存中的存储地址是某个特定值的倍数,这个特定值就是对齐系数。
常用的对齐系数有1、2、4、8等,根据不同的系统和编译器,对齐系数可能会有所不同。
二、结构体字节对齐的原理在C语言中,结构体的内存对齐是通过编译器来进行处理的。
当定义一个结构体时,编译器会按照一定的规则对结构体中的元素进行字节对齐,以便提高读取效率。
具体的对齐规则如下:1. 结构体中每个元素的偏移量必须是它自身类型大小的整数倍。
2. 结构体的大小必须是最大元素类型大小的整数倍。
3. 结构体的对齐系数为结构体中所有元素类型大小的最大值。
通过这些规则,编译器可以在编译时确定结构体的大小,并根据对齐系数进行内存对齐,从而提高内存访问的效率。
1. 使用#pragma pack指令在C语言中,可以使用#pragma pack指令来改变编译器默认的对齐系数。
通过指定pack(n)来设置n值,表示结构体的对齐系数为n。
这样可以在需要的时候自定义结构体的对齐系数,提高程序的效率。
```c#pragma pack(1)struct Student {char name[10];int age;float score;};```上面的代码中,通过#pragma pack(1)改变了结构体的对齐系数为1,从而可以确保结构体中的每个元素都按照一个字节进行对齐。
2. 使用__attribute__((packed))关键字在GCC编译器中,可以使用__attribute__((packed))关键字来实现对齐系数的设置。
c语言pragma的用法以下是 9 条关于 C 语言pragma 的用法:1. 嘿,你知道吗?pragma 可以用来指定编译器的一些特殊行为呢!就好像给编译器下达特别指令一样。
比如 pragma warning(disable: 4996),这就像是对编译器说:“嘿,别给我报 4996 这个警告啦!”2. 哇塞,pragma 还能优化代码的生成呢!像 pragma pack(1),这就像给代码的排列定下了严格规则,让其紧凑起来。
“哎呀,这样代码就更整齐啦!”3. 嘿呀,pragma 甚至可以影响代码的调试呢!像 pragma optimize("", off),这简直就是在说:“现在先别太着急优化,让我好好调试下!”4. 告诉你哦,pragma 能在一些特定情况下发挥大作用。
比如说 pragma once,就像是给文件加上了一个独特标记,“嘿嘿,这样就不会重复包含啦!”5. 哇哦,pragma 也能处理一些硬件相关的事情呢!像特定平台的指令设置,这多神奇呀,“这岂不是像给硬件开了个小后门?”6. 嘿嘿,pragma 有时候就像一个魔法开关。
比如控制某些警告的显示与否,“哇,这开关一扳,效果就不一样了呢!”7. 哟呵,pragma 还能针对代码的排版和风格做调整呢!像设置代码对齐方式,“嘿,这样代码看起来就更顺眼了呀!”8. 哈哈,pragma 真的好有趣呀!它可以根据你的需要灵活运用。
比如控制某些优化选项,“哇,这就像是给代码穿上了合适的衣服。
”9. 你想啊,pragma 就像是给 C 语言代码赋予了各种特别能力。
从优化到调试,从格式到硬件相关,无所不能。
“所以啊,一定要好好利用它呀!”我的观点结论:C 语言的 pragma 用法多样且神奇,能在很多方面为我们的代码编写带来便利和优化,真的是非常重要的一个部分呢!。
数据对齐详解一、数据对齐的原因大部分的参考资料都是如是说的:1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
二、对齐规则每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。
程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中的n 就是你要指定的“对齐系数”。
规则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset 为0 的地方,以后每个数据成员的对齐按照#pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行。
规则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack 指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
规则3:结合1、2 颗推断:当#pragma pack 的n 值等于或超过所有数据成员长度的时候,这个n 值的大小将不产生任何效果。
三、试验我们通过一系列例子的详细说明来证明这个规则吧!我试验用的编译器包括GCC 3.4.2 和VC6.0 的C 编译器,平台为Windows XP + Sp2。
我们将用典型的struct 对齐来说明。
首先我们定义一个struct:#pragma pack(n) /* n = 1, 2, 4, 8, 16 */struct test_t{int a;char b;short c;char d;};#pragma pack(n)首先我们首先确认在试验平台上的各个类型的size,经验证两个编译器的输出均为:sizeof(char) = 1sizeof(short) = 2sizeof(int) = 4我们的试验过程如下:通过#pragma pack(n)改变“对齐系数”,然后察看sizeof(struct test_t)的值。
c51结构体对齐方式
C51是一种常见的8位单片机,它使用的是Keil C51编译器。
在C51中,结构体的对齐方式是由编译器的设置和结构体成员的类型来决定的。
结构体对齐方式影响了结构体成员在内存中的存储方式,它可以通过编译器的设置来进行调整。
在C51中,默认的结构体对齐方式通常是按照成员的大小进行对齐,也就是说,结构体成员会被放置在能够容纳其大小的内存地址上。
这样做的好处是可以提高内存的访问效率,但是可能会导致内存空间的浪费。
另外,在C51中,也可以通过编译器的设置来指定结构体的对齐方式。
通过设置#pragma pack指令,可以改变默认的对齐方式,使得结构体成员按照指定的对齐方式进行排列。
例如,可以使用
#pragma pack(1)来指定按照1字节对齐,这样可以减少内存空间的浪费,但可能会影响内存的访问效率。
总的来说,C51中结构体的对齐方式可以通过编译器的设置来进行调整,可以根据实际的需求来选择合适的对齐方式,以达到内
存利用和访问效率的平衡。
结构体对齐方式的选择需要根据具体的应用场景和硬件平台来进行权衡和调整。
#pragma详细解释(一)默认分类 2010-04-18 14:21:00 阅读151 评论0 字号:大中小订阅在#Pragma是预处理指令它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为: #Pragma Para其中Para 为参数,下面来看一些常用的参数。
(1)message 参数。
Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
其使用方法为:#Pragma message(“消息文本”)当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。
假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法#ifdef _X86#Pragma message(“_X86 macro activated!”)#endif当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86 macro activated!”。
我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。
(2)另一个使用得比较多的pragma参数是code_seg。
格式如:#pragma code_seg( [\section-name\[,\section-class\] ] )它能够设置程序中函数代码存放的代码段,使用没有section-name字符串的#pragmacode_seg可在编译开始时将其复位,当我们开发驱动程序的时候就会使用到它。
(3)#pragma once (比较常用)只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
⼀篇⽂章带你了解C语⾔内存对齐公式⽬录⼀、前⾔⼆、公式2.1、例⼦⼀2.2、例⼦⼆2.3、例⼦三总结⼀、前⾔每⼀个特定平台上的编译器都有⾃⼰的默认“对齐系数”(也叫对齐模数)。
GCC中默认#program pack(4),即4个字节的内存对齐。
Keil也是采⽤4字节对齐的。
也可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这⼀系数,⼀般情况下尽量使⽤⾃然对齐系数,不要修改它。
STM32单⽚机上各个变量占⽤的字节数:⼆、公式公式⼀、结构体变量⾥,成员的起始地址必须满⾜:起始地址 % 成员的字节数(sizeof值)= 0 (说⽩了就是能整除)公式⼆、结构体变量的总字节数必须满⾜:总字节数 % 最⼤的成员字节数 = 0 (说⽩了就是能整除)2.1、例⼦⼀struct te_a{/* 公式⼀ */char a; /* a的起始地址0x00,然后⽤公式⼀计算:0x00 % 1(char为1个字节) = 0,所以成员a占⽤了内存0x00 */int b; /* b的起始地址0x01 % 4(int为4个字节)不等于0,那么再计算0x02%4还是不等于0,直到0x04 % 4 = 0 ,所以成员b占⽤了内存0x04 ~ 0x07 */char c; /* 成员b的结尾地址是0x07,所以成员c从0x08开始计算,那么计算0x08 % 1 = 0 , 所以成员c占⽤了内存0x08 */}Test1;OK,经过公式⼀的运算后,结构体⾥成员的分布如下:经过公式⼀的计算后,结构体变量Test1的⼤⼩是9个字节。
内存对齐的计算还没有结束,接着使⽤公式⼆计算:结构体变量的总字节数 % 最⼤的成员字节数 = 0 ,在结构体变量Test1⾥,最⼤的成员是b,b的⼤⼩是4个字节。
那么,当前的结构体变量⼤⼩9字节 % 4字节等于 0 。
当结构体变量⼤⼩为12字节 % 4字节 = 0,所以最终结构体变量Test1占⽤的内存字节数是12,其内存的分布如下:以上的都是根据公式计算出来的结果,那实际在单⽚机⾥是不是这样呢?把代码下载到STM32单⽚机⾥,进⼊DEBUG模式看看。
#Pragma是预处理指令,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为: #Pragma Para其中Para 为参数,下面来看一些常用的参数。
(1)message 参数。
Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
其使用方法为:#Pragma message(“消息文本”)当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。
假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法#ifdef _X86#Pragma message(“_X86 macro activated!”)#endif当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86 macro activated!”。
我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。
(2)另一个使用得比较多的pragma参数是code_seg。
格式如:#pragma code_seg( [\section-name\[,\section-class\] ] )它能够设置程序中函数代码存放的代码段,使用没有section-name字符串的#pragmacode_seg可在编译开始时将其复位,当我们开发驱动程序的时候就会使用到它。
(3)#pragma once (比较常用)只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
pragma用法Pragma用法详解Pragma是一种指令,用于告诉编译器如何处理代码。
在C和C++中,Pragma指令通常用于控制编译器的优化行为、警告行为、对齐方式等。
本文将详细介绍Pragma的用法。
1.优化指令#pragma GCC optimize("O2") //开启O2优化#pragma GCC optimize("Ofast") //开启Ofast优化#pragma GCC optimize("Os") //开启Os优化#pragma GCC optimize("Og") //开启Og优化2.警告指令#pragma GCC diagnostic error "-Wformat" //将格式化警告转换为错误#pragma GCC diagnostic warning "-Wuninitialized" //将未初始化变量警告转换为警告#pragma GCC diagnostic ignored "-Wunused-variable" //忽略未使用变量警告3.对齐指令#pragma pack(1) //按1字节对齐#pragma pack(2) //按2字节对齐#pragma pack(4) //按4字节对齐4.循环展开指令#pragma GCC unroll 2 //展开2次循环#pragma GCC unroll 4 //展开4次循环#pragma GCC unroll 8 //展开8次循环5.函数属性指令#pragma GCC optimize("inline-functions") //将函数内联#pragma GCC optimize("no-inline-functions") //禁止函数内联#pragma GCC optimize("no-stack-protector") //禁用堆栈保护6.链接指令#pragma GCC visibility push(hidden) //隐藏符号#pragma GCC visibility pop //取消隐藏符号7.其他指令#pragma GCC poison printf //禁止使用printf函数#pragma GCC dependency "file.h" //指定依赖文件总结以上是Pragma指令的常见用法,可以根据需要选择使用。
#pragmapack使⽤⽅法
1 起因
在通信协议中使⽤定义通信帧结构体变量时,因为结构体中包含多个变量,各⾃所占的字节数也不同,编译器会默认⽤对应最⼤字节数来编译各个变量。
这样会带来两个问题:
1)内存资源的浪费;
2)在通讯帧解析函数中,⽤sizeof函数来计算结构体所占字节数,不是实际的字节长度。
2 说明
使⽤#pragma pack(n)设定变量以n字节对齐时,存在两种形式:
1)n⼤于该变量所占字节数,偏移量使⽤默认的对齐⽅式;
2)n⼩于该变量所占字节数,偏移量为n的倍数。
3 demo
1#pragma pack (n)
2//等价于上⾯的
3//#pragma pack(push,n)
4//作⽤:指定按n字节对齐
5struct A{
6char b; //1 byte
7int a; //4 bytes
8short c; //2 bytes
9 };
10//#pragma pack(pop)
11//等价于下⾯
12//作⽤:取消指定对齐,恢复缺省对齐
13#pragma pack()
如果上⾯的是按1个字节对齐,那么sizeof(struct A)的值为7;
如果是编译器默认的⽅式,sizeof(struct A)的值为12。
注意:
1)#pragma pack(n)⼀定要与#pragma pack()配合使⽤;
2)⼀般令n=1,即#pragma pack(1)即可。
⼤端和⼩端--内存对齐问题什么是⼤端和⼩端Big-Endian和Little-Endian的定义如下:1) Little-Endian就是低位字节排放在内存的低地址端,⾼位字节排放在内存的⾼地址端。
2) Big-Endian就是⾼位字节排放在内存的低地址端,低位字节排放在内存的⾼地址端。
举⼀个例⼦,⽐如数字0x12 34 56 78在内存中的表⽰形式为:1)⼤端模式:低地址 -----------------> ⾼地址0x12 | 0x34 | 0x56 | 0x782)⼩端模式:低地址 ------------------> ⾼地址0x78 | 0x56 | 0x34 | 0x12可见,⼤端模式和字符串的存储模式类似。
3)下⾯是两个具体例⼦:16bit宽的数0x1234在Little-endian模式(以及Big-endian模式)CPU内存中的存放⽅式(假设从地址0x4000开始存放)为:内存地址⼩端模式存放内容⼤端模式存放内容0x40000x340x120x40010x120x3432bit宽的数0x12345678在Little-endian模式以及Big-endian模式)CPU内存中的存放⽅式(假设从地址0x4000开始存放)为:内存地址⼩端模式存放内容⼤端模式存放内容0x40000x780x120x40010x560x340x40020x340x560x40030x120x784)⼤端⼩端没有谁优谁劣,各⾃优势便是对⽅劣势:⼩端模式:强制转换数据不需要调整字节内容,1、2、4字节的存储⽅式⼀样。
⼤端模式:符号位的判定固定为第⼀个字节,容易判断正负。
数组在⼤端⼩端情况下的存储: 以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以⽤unsigned char buf[4]来表⽰value: Big-Endian: 低地址存放⾼位,如下:⾼地址---------------buf[3] (0x78) -- 低位buf[2] (0x56)buf[1] (0x34)buf[0] (0x12) -- ⾼位---------------低地址Little-Endian: 低地址存放低位,如下:⾼地址---------------buf[3] (0x12) -- ⾼位buf[2] (0x34)buf[1] (0x56)buf[0] (0x78) -- 低位--------------低地址为什么会有⼤⼩端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit。
字节对齐详解分类:Linux系统编程2009-07-11 10:31 185人阅读评论(0) 收藏举报一.什么是字节对齐,为什么要对齐?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。
一些平台对某些特定类型的数据只能从某些特定地址开始存取。
比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。
比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。
显然在读取效率上下降很多。
二.字节对齐对程序的影响:先让我们看几个例子吧(32bit,x86环境,gcc编译器):设结构体如下定义:struct A{int a;char b;short c;};struct B{char b;int a;short c;};现在已知32位机器上各种数据类型的长度如下:char:1(有符号无符号同)short:2(有符号无符号同)int:4(有符号无符号同)long:4(有符号无符号同)float:4 double:8那么上面两个结构大小如何呢?结果是:sizeof(strcut A)值为8sizeof(struct B)的值却是12结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字节。
#pragma指令用法汇总和解析一. message 参数。
message它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
其使用方法为:#pragma message(“消息文本”)当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。
假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法#ifdef _X86#pragma message(“_X86 macro activated!”)#endif当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86 macro activated!”。
我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了二. 另一个使用得比较多的#pragma参数是code_seg。
格式如:#pragma code_seg( [ [ { push | pop}, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] ) 该指令用来指定函数在.obj文件中存放的节,观察OBJ文件可以使用VC自带的dumpbin命令行程序,函数在.obj文件中默认的存放节为.text节如果code_seg没有带参数的话,则函数存放在.text节中push (可选参数) 将一个记录放到内部编译器的堆栈中,可选参数可以为一个标识符或者节名pop(可选参数) 将一个记录从堆栈顶端弹出,该记录可以为一个标识符或者节名identifier (可选参数) 当使用push指令时,为压入堆栈的记录指派的一个标识符,当该标识符被删除的时候和其相关的堆栈中的记录将被弹出堆栈"segment-name" (可选参数) 表示函数存放的节名例如://默认情况下,函数被存放在.text节中void func1() { // stored in .text}//将函数存放在.my_data1节中#pragma code_seg(".my_data1")void func2() { // stored in my_data1}//r1为标识符,将函数放入.my_data2节中#pragma code_seg(push, r1, ".my_data2")void func3() { // stored in my_data2}int main() {}三. #pragma once (比较常用)这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次四. #pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。