#pragma
一般用法
#pragma parameter
不同的 parameter 参数语发和意义不相同, 不同编译器对它有不同的编译方式.
,
#pragma message
#pragma message 与 #error 和 #waring 不同,它仅代表一条编译消息,不代表程序错误。
#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;
}
在不同的编译器效果不一样
[GCC] test.c:10: note: #pragma message: Compile Android SDK 4.0...
[VC] Compile Android SDK 4.0...
#pragma once
#ifndef __HEAD_FILE_
#define __HEAD_FILE_
// ...
#endif
VS
#pragma once
#pragma once 效率高,但是在不同的编译器有不同的表现,比如在GCC下是被支持的 BCC是不支持的。
一个保证适用不同编译器又保证效率的写法,这样的移植更好!!
#ifndef __HEAD_FILE_
#define __HEAD_FILE_
#pragma once
// ...
#endif
#pragma Pack
内存对齐(嵌入式开发中很重要的一个)
不同类型的数据在内存中按照一定的规则排列,而不一定是按照顺序的一个接一个的排序。
struct Test1
{
char c1;
short s;
char c2;
int i;
};
struct Test2
{
char c1;
char c2;
short s;
int i;
};
Test1 和 Test2 内存分布的方示意图
造成这样的原因是因为:
CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1,2,4,8,16 字节,当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣,因此编译器编译的时候会使它对齐,提高读取速度。某些硬件平台只能从规定的相对地址读取特定类型的数据,否则会产生硬件异常。
#pragma Pack 用于指定内存对齐方式
规则:Struct占用的内存大小:
- 第一个成员起始于0偏移处
- 每个成员按其类型大小和pack参数中较小一个作为(对齐参数)
- 偏移地址必须能被 对齐参数整除,
- 结构体成员的大小取其内部长度最大的数据成员作为其大小。
- 结构体总长度必需为所有对齐参数的整数倍
注意:
上一个偏移地址+大小,作为下一个参数的偏移地址(当然还要判断偏移地址能不能作为的条件)最终的占用的大小是最后变量的偏移地址+大小(当然还要计算:结构体总长度必需为所有对齐参数的整数倍).
练习一
#pragma pack(4)
struct Test1
{ // 对齐参数 偏移地址 大小
char c1; // 1 0 1
short s; // 2 2 2
char c2; // 1 4 1
int i; // 4 8 4
};
#pragma pack()
#pragma pack(2)
struct Test2
{ // 对齐参数 偏移地址 大小
char c1; // 1 0 1
short s; // 2 2 2
char c2; // 1 4 1
int i; // 2 6 4
};
#pragma pack()
#pragma pack(4)
struct Test3
{ // 对齐参数 偏移地址 大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 2 2 2
int i; // 4 4 4
};
#pragma pack()
Tes11 大小为12
Test2 大小为10
Test3 大小为8
练习二:
#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; // 4 12 8
};
#pragma pack()
S1 8字节
S2 20字节
练习二中 GCC编译器暂时不支持8字节对齐 #pragma pack(8),因为不支持就直接按照4字节对齐#pragma pack(4)
小结
#pragma 用于指示编译器完成一些特定的动作
#pragma 所定义的很多指示字都是编译器特有的
- #pragma message 用于自定义编译消息
- #pragma once 用于保证头文件只被编译一次
- #pragma pack 用于指定内存对齐方式