目录
1、#pragma简介
#pragma用于指示编译器完成一些特定的动作
#pragma所定义的很多指示字是编译器特有的
#pragma在不同的编译器间是不可移植的
-预处理器将忽略它不认识的#pragma指令
-不同的编译器可能以不同的方式解释同—条#pragma指令
一般用法:
#pragma parameter
注:不同的parameter参数语法和意义各不相同
2、#pragma message
message参数在大多数的编译器中都有相似的实现
message参数在编译时输出消息到编译输出窗口中
message用于条件编译中可提示代码的版本信息
#if defined(ANDROID20)
#pragma message("Compile Android SDK 2.0…")
#define VERSION "Android 2.0 "
#endif
与#error和#warning不同,#pragma message 仅仅代表一条编译消息,不代表程序错误。
实例分析
#pragma message使用示例 test.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!
#endif
int main()
{
printf("%s\n", VERSION);
return 0;
}
gcc
VS2015
BCC
3、#pragma once
#pragma once用于保证头文件只被编译—次
#pragma once是编译器相关的,不—定被支持
这两种方式有什么区别?
通过宏可以保证头文件里的内容只被嵌入一次但可能包含了多次,预处理
器依然处理了多次,所以从效率上说它要打折扣,而pragam once 告诉
预处理器当前文件只被编译一次(即只被include一次,多余的都不会处理),
所以它的编译效率会高很多,然而大多数工程使用#ifndef方式,原因在于
不是所有的编译器都支持once这个参数,#ifndef是C语言所支持的
实例分析
#pragma once使用分析 test.c
global.h
#pragma once
int g_value = 1;
test.c
#include <stdio.h>
#include "global.h"
#include "global.h"
int main()
{
printf("g_value = %d\n", g_value);
return 0;
}
在VS2015同样支持,然而在BCC5.5.1会报错,即不支持once参数
global.h
#ifndef _GLOBAL_
#define _GLOBAL_
#pragma once
int g_value = 1;
#endif
实际工程中往往用这种方式保证移植性和高效性
此时在BCC5.5.1上可以编译成功
4、#pragma pack
什么是内存对齐?
-不同类型的数据在内存中按照一定的规则排列
-而不一定是顺序的一个接一个的排列
Test1和Test2所占的内存空间是否相同?
为什么需要内存对齐?
- CPU对内存的读取不是连续的,而是分成块读取的,
块的大小只能是1、2, 4, 8, 16 .. 字节
-当读取操作的数据未对齐,则需要两次总线周期来访
问内存,因此性能会大打折扣
-某些硬件平台只能从规定的相对地址处读取特定类型的
数据,否则产生硬件异常
例题:
#pragma pack用于指定内存对齐方式
#pragma pack能够改变编译器的默认对齐方式
struct占用的内存大小
-第一个成员起始于0偏移处
-每个成员按其类型大小和pack参数中较小的一个进行对齐
★ 偏移地址必须能被对齐参数整除
★ 结构体成员的大小取其内部长度最大的数据成员作为其大小
-结构体总长度必须为所有对齐参数的整数倍
-编译器在默认情况下按照4字节对齐。
编程实验
结构体大小计算
test.c
#include <stdio.h>
#pragma pack(2)
struct Test1
{
char c1; //1 0 1
short s; //2 2 2
char c2; //1 4 1
int i; // 2 6 4//10
};
#pragma pack()
#pragma pack(4)
struct Test2
{
char c1;
char c2;
short s;
int i;
};
#pragma pack()
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}
test.c(微软面试题)
#include <stdio.h>
#pragma pack(8)
struct S1
{
short a; //2 0 2
long b; //4 4 4-->8 这里按long为4
};
struct S2
{
char c; //1 0 1
struct S1 d; //4 4 8 // 结构体成员的大小取其内部长度最大的数据成员作为其大小和pack参数对比 ,对齐参数为4
double e; // 8 16 8--->24
};
#pragma pack()
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
gcc version 6.3.0
说明这个版本编译器不支持pack参数,用的默认参数,4,结果为20
VS2015(BCC)
小结
#pragma用于指示编译器完成—些特定的动作
#pragma所定义的很多指示字是编译器特有的
- #pragma message用于自定义编译消息
- #pragma once用于保证头文件只被编译—次
- #pragma pack用于指定内存对齐方式
扩展:
#pragma comment( comment-type, ["commentstring"] )
comment-type:可选项compliler,lib,linker,exestr,最常用的是lib
如:#pragma comment(lib, "A.lib") 将A静态库加入本工程
否者我们就需要将A.h和A.lib分别放入...\VC\include\和...\VC\lib\目录下,再自己配置IDE链接时加上该库