#pragma预处理分析
来源:互联网 发布:win2008端口转发 编辑:程序博客网 时间:2024/06/06 00:10
编译预处理
专题三:编译预处理。包括以下章节:
- 编译过程简介
- 宏定义与宏使用分析
- 条件编译使用分析
- #error和#line
- #pragma预处理分析
- #和##运算符使用解析
#pragma
- #pragma是编译器指示字,用于指示编译器完成一些特定的动作
- #pragma所定义的很多指示字是编译器和操作系统特有的
- #pragma在不同的编译器间是不可移植的
- 预处理器将忽略它不认识的#pragma指令
- 两个不同的编译器可能以两种不同的方式解释同一条#pragma指令
#pragma message
- message参数在大多数的编译器中都有相似的实现
- message参数在编译时输出消息到编译输出窗口中
- message可用于代码的版本控制
- message是VC特有的编译 器指示字,GCC中将其忽略。(低版本的gcc忽略,但是高版本的gcc会打印附注信息)
实例分析5-1:#pragma message在不同编译器下不同实现
5-1.c
#include <stdio.h>#if defined(ANDROID20)#pragma message("Compile Android SDK 2.0...")#define VERSION "Android 2.0"#elif defined(ANDROID23)#pragma message("Compile Android SDK 2.3...")#define VERSION "Android 2.3"#elif defined(ANDROID40)#pragma message("Compile Android SDK 4.0...")#define VERSION "Android 4.0"#else#error Compile Version is not provided!#endifint main(){ printf("%s\n", VERSION); return 0;}
结果:
#pragma pack
不同类型的数据在内存中按照一定的规则排列;而不是顺序的一个接一个的排放,这就是对齐。
为什么需要内存对齐?
- CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1、2、4、8、16字节
- 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
- 某些硬件平台只能从规定的地址处取某些特定类型的数据,否则抛出硬件异常(比如某些硬件只能读取偶数内存地址的值)
#pragma pack能够改变编译器的默认对齐方式
struct占用的内存大小
- 第一个成员起始于0偏移处
- 每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐
– 偏移地址和成员占用大小均需对齐
– 结构体成员的对齐参数为其所有成员使用的对齐参数的最大值 - 结构体总长度必须为所有对齐参数的整数倍
5-2.c
#include<stdio.h>#pragma pack(2)struct Test1{ //假如首地址是0x0000 char c1;//大小1Byte,1和2比较1小,所以起始地址:0,内存地址:0x0000 short s;//大小2Byte,2和2比较等同,所以起始地址:2,内存地址:0x0002 0x0003 char c2;//大小1Byte,1和2比较1小,所以起始地址:4,内存地址:0x0004 int i; //大小4Byte,4和2比较2小,所以起始地址:6,内存地址:0x0006 0x0007 0x0008 0x0009};#pragma pack()#pragma pack(4)struct Test2{ //假如首地址是0x0000 char c1;//大小1Byte,1和4比较1小,所以起始地址:0,内存地址:0x0000 char c2;//大小1Byte,1和4比较1小,所以起始地址:1,内存地址:0x0001 short s;//大小2Byte,2和4比较2小,所以起始地址:2,内存地址:0x0002 0x0003 int i; //大小4Byte,4和4比较等同,所以起始地址:4,内存地址:0x0004 0x0005 0x0006 0x0007 };#pragma pack()#pragma pack(4)struct Test3{ //假如首地址是0x0000 char c1;//大小1Byte,1和4比较1小,所以起始地址:0,内存地址:0x0000 short s;//大小2Byte,2和4比较2小,所以起始地址:2,内存地址:0x0002 0x0003 char c2;//大小1Byte,1和4比较1小,所以起始地址:4,内存地址:0x0004 int i; //大小4Byte,4和4比较等同,所以起始地址:8,内存地址:0x0008 0x0009 0x000A 0x000B};#pragma pack()int main(){ printf("%lu\n", sizeof(struct Test1)); printf("%lu\n", sizeof(struct Test2)); printf("%lu\n", sizeof(struct Test3)); return 0;}
结果:
实例分析5-2:Intel和微软面试题
5-3.c
#include<stdio.h>//结构体中的成员大小与对齐参数进行比较,小的那个数是对齐数,不一定必须是8#pragma pack(8)struct S1{ //假如首地址是0x0000 short a;//大小2Byte,2和8比较2小,所以起始地址:0 long b; //大小8Byte,8和8比较等同,所以起始地址:8 //所以,struct S1内存中占16字节(0x0000~0x000F)};struct S2{ //假如首地址是0x0000 char c; //大小1Byte,1和8比较1小,所以起始地址:0 struct S1 d;//大小16Byte,16和8比较8小,所以起始地址:8 double e; //大小8Byte,8和8比较等同,所以起始地址:(24)0x0018 //所以,struct S2内存中占32字节(0x0000~0x001F)};#pragma pack()int main(){ struct S2 s2; printf("%lu\n", sizeof(struct S1)); printf("%lu\n", sizeof(struct S2)); //s2.c的内存地址和s2.d的内存地址相差8字节 //s2.c占1字节,而剩余7字节(8字节对齐)无法装下s2.d(16字节)。所以剩余7字节为空,s2.c地址偏移8个字节开始装s2.d。 printf("%d\n", (int)&(s2.d) - (int)&(s2.c)); return 0;}
结果:
然而在VC上编译结果却不同
5-3.c
#include<stdio.h>#pragma pack(8)struct S1{ //假如首地址是0x0000 short a;//大小2Byte,2和8比较2小,所以起始地址:0 long b; //大小4Byte,4和8比较4小,所以起始地址:4 //所以,struct S1内存中占8字节(0x0000~0x0007)};struct S2{ //假如首地址是0x0000 char c; //大小1Byte,1和8比较1小,所以起始地址:0 struct S1 d;//大小8Byte,(结构体成员的对齐参数为其所有成员使用的对齐参数的最大值,是4)4和8比较4小,所以起始地址:4 double e; //大小8Byte,8和8比较等同,所以起始地址:(16)0x0010 //所以,struct S2内存中占24字节(0x0000~0x0017)};#pragma pack()int main(){ struct S2 s2; printf("%lu\n", sizeof(struct S1)); printf("%lu\n", sizeof(struct S2)); printf("%d\n", (int)&(s2.d) - (int)&(s2.c)); return 0;}
结果:
阅读全文
0 0
- #pragma 预处理指令分析
- #pragma预处理分析
- 3.4、#pragma预处理分析
- #pragma预处理分析
- #pragma 预处理
- 预处理pragma
- 专题3-5.#pragma预处理分析(国嵌C语言视频)
- #pragma预处理分析 和 struct 结构体大小的计算
- #pragma 预处理指令详解
- #pragma 预处理指令详解
- #pragma 预处理指令详解
- #pragma 预处理指令详解
- #pragma 预处理指令详解
- #pragma 预处理指令详解
- #pragma预处理指令详解
- #pragma预处理指令详解
- #pragma 预处理指令详解- -
- #pragma 预处理指令详解
- SpringBoot入门
- 简单介绍一些matlab常用的函数(1)
- Hyper-v虚拟机下Ubuntu Server 14.04 配置网络
- OkHttp
- 《Netty in Action》chapter 6 : ChannelHandler and ChannelPipeline
- #pragma预处理分析
- cf
- RxAndroid: 基础介绍(一)
- How tomcat works——序言
- var const let 三者之间的区别
- Swig在Mac OS X上的安装
- 淘淘商城系列——jsonp的原理及两种实现方式
- 解决
- Oracle Sqlplus命令登录的几种方式