- #pragma 用于指示编译器完成一些特定的动做
- #pragma 所定义的不少指示字是编译器特有的
#pragma 在不一样的编译器间是不可移植的编程
- 预处理器将忽略它不认识的#pragma指令
- 不一样的编译器可能以不一样的方式解析同一条#pragma指令
通常用法:ide
'#pragma parameter' 注: 不一样的 parameter 参数语法和意义各不相同
C 语言预留给编译器厂商的扩展指示字性能
- message 参数在大多数的编译器中都有类似的实现
- message 参数在编译时输出消息到编译输出窗口中
- message 用于条件编译中可提示代码的版本信息
#if defined(ANDROID20) #pragma message("Compile Android SDK 2.0 ...") #define VERSION "Android 2.0" #endif
与 #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; }
编译输出: [GCC] test.c:10: note: #pragma message: Compile Android SDK 4.0... [VC] Compile Android SDK 4.0... 运行输出: [GCC] Android 4.0 [VC] Android 4.0
- #pragma once 用于保证头文件只被编译一次
- #pragma once 是编译器相关的,不必定被支持
#ifndef _HEADER_H_ #define _HEADER_H_ // source code #endif
与spa
#pragma once
code
这两种方式有什么区别呢?ip
Test.c内存
#include <stdio.h> #include "global.h" #include "global.h" int main() { printf("g_value = %d\n", g_value); return 0; }
global.h编译器
#pragma once int g_value = 1;
输出: g_value = 1 VC GCC : 无警告,无错误 【主持】 BCC : 编译出错, g_value屡次定义 【不支持】
#ifndef _HEADER_H_ #define _HEADER_H_ #pragma once // source code #endif
什么是内存对齐it
- 不一样类型的数据在内存中按照必定的规则排列
- 而不必定是顺序的一个接一个的排列
struct Test1 { char c1; short s2; char c2; int i; }; struct Test2 { char c1; char c2; short s2; int i; };
Test1 和 Test2 所占的内存空间是否相同?io
sizeof(struct Test1) = 12
sizeof(struct Test2) = 8
CPU 对内存的读取不是连续的,而是分红块读取的,块的大小只能是一、二、四、八、16...字节
- 当读取操做的数据未对齐,则须要两次总线来访问内存,所以性能会大打折扣
- 某些硬件平台只能从规定的相对地址读取特定类型的数据,不然产生硬件异常
- #pragm pack 用于指定内存对齐方式
未对齐形成两次内存读取【32位机器的读写最小粒度4字节】
#pragma pack(1) struct Test1 { char c1; short s2; char c2; int i; }; #pragma pack() #pragma pack(1) struct Test2 { char c1; char c2; short s2; int i; }; #pragma pack()
sizeof(struct Test1) = 8
sizeof(struct Test2) = 8
- 第一个成员起始于 0 偏移处
每一个成员按其类型大小和pack参数中较小的一个进行对齐
- 偏移地址必须能被对齐参数整除
- 结构体成员的对齐参数大小取其内部pack参数与内部长度最大的数据成员之间较小的做为其对齐参数大小
- 结构体总长度必须为全部对齐参数的整数倍
编译器默认状况下按照 4 字节对齐
编程实验: 结构体大小计算
Test_1.c
#include <stdio.h> #pragma pack(2) struct Test1 { // 对齐参数 偏移地址 大小 char c1; // 1 0 1 short s2; // 2 2 2 char c2; // 1 5 2 int i; // 2 6 4 }; #pragma pack() #pragma pack(4) struct Test2 { // 对齐参数 偏移地址 大小 char c1; // 1 0 1 char c2; // 1 1 1 short s2; // 2 2 2 int i; // 4 4 4 }; #pragma pack() int main() { printf("%d\n", sizeof(struct Test1)); printf("%d\n", sizeof(struct Test2)); }
输出: 10 8
Test_2.c
#include <stdio.h> #pragma pack(8) struct S1 { // 对齐参数 偏移地址 大小 short s; // 2 0 1 long b; // 4 4 4 }; // 总体长度为全部对齐参数的整数倍, len = 4 + 4 = 8 struct S2 { // 对齐参数 偏移地址 大小 char c; // 1 0 1 struct S1 d; // 4 4 8 double e; // 8 16 8 }; // 总体长度为全部对齐参数的整数倍 , len = 8 + 16 = 24 #pragma pack() int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); }
输出:[GCC] 8 20 【截至2018/12/04,GCC 暂不支持8字节对齐,忽略pack(8),默认4字节对齐】 输出:[VC] 8 20
- #pragma 用于指示编译器完成一些特定的动做
#pragma 所定义的不少指示字都是编译器特有的
- #pragma message 用于自定义编译消息
- #pragma once 用于保证头文件只被编译一次
- #pragma pack 用于指定内存对齐方式
以上内容参考狄泰软件学院系列课程,请你们保护原创!