C语言学习笔记14——#pragma使用分析
程序员文章站
2022-05-05 10:25:55
...
#pragma简介
#pragma 用于指示编译器完成一些特定的动作
#pragma 所定义的很多指示字是编译器特有的
-
#pragma 在不同的编译器间是不可移植的
- 预处理器将忽略他不认识的#pragma指令
- 不同的编译器可能以不同的方式解释同一条#pragma指令
用法:
#pragma parameter
注:不同的parameter参数语法和意义各不相同
#pragma的分析1:#pragma message
message 参数在大多数的编译器中都有相似的实现
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;
}
运行结果
delphi@delphi-vm:~$ gcc -DANDROID20 text.c
text.c:5: note: #pragma message: Compile Android SDK 2.0...
delphi@delphi-vm:~$ ./a.out
Android 2.0
#pragma的分析2:#pragma once
- #pragma once 用于保证头文件只被编译一次
- #pragma once 是编译器相关的, 不一定被支持
/*
测试代码
global.h
*/
#pragma once
int g_value = 1;
/*
测试代码
主程序
main.c
*/
#include <stdio.h>
#include "global.h"
#include "global.h"
int main()
{
printf("g_value = %d\n", g_value);
return 0;
}
运行结果
g_value = 1
#pragma的分析3:#pragma pack
#pragma pack 用于指定内存对齐方式
-
什么是内存对齐?
不同类型的数据在内存中按照一定的规律排列
而不一定是顺序的一个一个的排列
-
为什么需要内存对齐?
CPU 对内存的读取不是连续的, 而是分块读取的, 块的大小只能是 1, 2, 4, 8, 16 …字节
当读取操作的数据未对齐, 则需要两次总线周期来访问内存, 因此性能会大打折扣
某些硬件平台只能从常规的相对地址读取特定类型的数据, 否则产生硬件异常
-
如何内存对齐?
编译器在默认情况下按照 4字节对齐(#pragma pack(4))
#pragma pack 能够改变编译器的默认对齐方式
-
计算struct占用的内存大小
第一个成员起始于0 偏移处
每个成员按其类型大小和pack参数中较小的一个进行对齐
偏移地址必须能被对齐参数整除
结构体类型大小取其内部长度最大的数据成员作为其大小
结构体总长度必须为所有对齐参数的整数倍
/*
测试代码
结构体默认对齐方式为 4 字节
因为内存对齐, struct Test1 和 struct Test2 内成员相同, 但占用的内存不同
*/
#include <stdio.h>
struct Test1
{ // 对齐参数 偏移地址 占内存大小
char c1; // 1 0 1
short s; // 2 2 2
char c2; // 1 4 1
int i; // 4 8 4
}; // sizeof(struct Test1) == 8 + 4 == 12
struct Test2
{ // 对齐参数 偏移地址 占内存大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 2 2 2
int i; // 4 4 4
}; // sizeof(struct Test2) == 4 + 4 == 8
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1)); // sizeof(Test1) = 12
printf("sizeof(Test2) = %d\n", sizeof(struct Test2)); // sizeof(Test2) = 8
return 0;
}
/*
测试代码
利用 #pragma pack 改变默认对齐方式
重新计算 struct Test1 和 struct Test2 占用的内存大小
*/
#include <stdio.h>
#pragma pack(1)
struct Test1
{ // 对齐参数 偏移地址 占内存大小
char c1; // 1 0 1
short s; // 1 1 2
char c2; // 1 3 1
int i; // 1 4 4
}; // sizeof(struct Test1) == 4 + 4 == 8
#pragma pack()
#pragma pack(1)
struct Test2
{ // 对齐参数 偏移地址 占内存大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 1 2 2
int i; // 1 4 4
}; // sizeof(struct Test2) == 4 + 4 == 8
#pragma pack()
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1)); // 8
printf("sizeof(Test2) = %d\n", sizeof(struct Test2)); // 8
return 0;
}
上一篇: 聊聊跨域那些事
下一篇: CAS单点登录3--服务端登录页个性化