#pragma用于指示完成一些特定的动作,并且所定义的很多指示字是编译器特有的。
#pragma在不同的编译器间是不可移植的:
——预处理器将忽略它不认识的#pragma指令
——不同的编译器可能以不同的方式解释一条#pragma指令。
一般用法:
#pragma parameter
注:不同的parameter参数语法和意义各不相同
message参数在大多数的编译器中都有相似的实现;message参数在编译时输出消息到编译输出窗口中。
与#error和#warning不同,#pragma message仅仅代表一条编译消息,不代表程序错误。
#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!
#endif
int main()
{
printf("%s\n", VERSION);
return 0;
}
在Linux下使用GCC进行编译:
~/will$ gcc 24-1.c //直接编译
24-1.c:13: error: #error Compile Version is not provided!
24-1.c: In function ‘main’:
24-1.c:18: error: ‘VERSION’ undeclared (first use in this function)
24-1.c:18: error: (Each undeclared identifier is reported only once
24-1.c:18: error: for each function it appears in.)
~/will$
~/will$
~/will$ gcc -DANDROID23 24-1.c // 条件编译
24-1.c:7: note: #pragma message: Compile Android SDK 2.3... //与VC不同的是,BCC和GCC将 #pragma message: 打印出来
~/will$
~/will$
~/will$ ./a.out //运行
Android 2.3
#pragma once
#pragma once 用于保证头文件纸杯编译一次;#pragma once 是编译器相关,不一定被支持。
pragma once是部分编译器支持;预处理器遇见pragma once后将直接忽略再次出现的头文件
#pragma pack 内存对齐
——不同类型的数据在内存中按照一定的规则排列
——而不一定是顺序的一个接一个的排列
为什么需要内存对齐?
——CPU对内存的读取不是连续的,而是分成块读取的,快的大小只能是1,2,4,8,16...字节;
——当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣;
——某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常。
#pragma pack用于指定“内存对齐”方式。
#include <stdio.h>
#pragma pack(4)
struct Test1
{ //对齐参数 偏移地址 大小
char c1; //1 0 1(4)
short s; //2 2 2
char c2; //1 4 1(4)
int i; //4 8 4
};
#pragma pack()
#pragma pack(4)
struct Test2
{ //对齐参数 偏移地址 大小
char c1; //1 0 1
char c2; //1 1 1
short s; //2 2 2
int i; //4 4 4
};
#pragma pack()
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}
编译运行:
~/will$ ./a.out
sizeof(Test1) = 12
sizeof(Test2) = 8
Gcc编译器暂时不支持8字节对齐。
struct占用的内存大小:
——第一个成员起始于0偏移处;
——每个成员按其类型大小和pack参数中较小的一个进行对齐;
偏移地址必须能被对齐参数整除;
结构体成员的大小取其内部长度最大的数据成员作为其大小;
结构体总长度必须为所有对齐参数的整数倍
注意:编译器在默认情况下按照4字节对齐。#include <stdio.h>
#pragma pack(8)
struct S1
{ //对齐参数 偏移地址 大小
short a; //2 0 2
long b; //4 4 4
};
struct S2
{ //对齐参数 偏移地址 大小
char c; //1 0 1
struct S1 d; //4 4 8
double e; //8 16 8
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
Gcc编译器暂时不支持8字节对齐,输出为8
20
在vc编译器支持8字节对齐,输出为8
24
小结:
#pragma用于指示编译器完成一些特定的动作
#pragma所定义的很多指示字是编译器特有的
——#pragma message用于自定义编译消息——#pragma once用于保证头文件只被编译一次
——#pragma pack用于指定内存对齐方式