关键词:#pragma
简介、#pragma message
、#pragma one
、 内存对齐、#pragma pack
、struct
占用的内存大小计算方式
1. #pragma
简介
-
#pragma
用于指示编译器完成一些特定的动作 -
#pragma
所定义的很多指示字是编译器特有的 -
#pragma
在不同的编译器间是不可移植的
预处理器将忽视它不认识的#pragma
指令
不同的编译器可能以不同的方式解释同一条#pragma
指令 - 用法
#pragma parameter
:不同的parameter
参数语法和意义各不相同
2. #pragma message
-
message
参数在大多数的编译器中都有相似的实现 -
message
参数在编译时输出消息到编译输出窗口中 -
message
用于条件编译中可提示代码版本信息
#include <stdio.h>
#if defined(ANDROID20)
#pragma message("Compile Android SDK 2.0...")
#define VERSION "Android 2.0"
#elif defined(ANDROID30)
#pragma message("Compile Android SDK 3.0...")
#define VERSION "Android 3.0"
#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 -DANDROID30 1.c
输出结果:
Android 3.0
3. #pragma one
-
#pragma one
用于保证头文件只被编译一次 -
#pragma one
与编译器相关,不一定被支持 - 在工程中的使用:
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
#pragma once
// source code
#endif
4. 内存对齐
- 不同类型的数据在内存中按照一定的规则排列的,而不一定是顺序的一个接一个的排列
- 下面两个结构体所占的内存空间是否相同?
#include <stdio.h>
struct Test1
{
char c1;
short s;
char c2;
int i;
};
struct Test2
{
char c1;
char c2;
short s;
int i;
};
int main()
{
printf(" sizeof(struct Test1) = %d\n sizeof(struct Test2) = %d\n", sizeof(struct Test1), sizeof(struct Test2));
return 0;
}
输出结果:
sizeof(struct Test1) = 12
sizeof(struct Test2) = 8
5. 为什么需要内存对齐?
- CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是1、2、4、8、16...字节
- 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
- 某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常
-
#pragma pack
用于指定内存对齐方式
6. #pragma pack
-
#pragma pack
能够改变编译器的默认对齐方式
#include <stdio.h>
#pragma pack(1)
struct Test1
{
char c1;
short s;
char c2;
int i;
};
#pragma pack()
#pragma pack(1)
struct Test2
{
char c1;
char c2;
short s;
int i;
};
#pragma pack()
int main()
{
printf(" sizeof(struct Test1) = %d\n sizeof(struct Test2) = %d\n", sizeof(struct Test1), sizeof(struct Test2));
return 0;
}
输出结果:
sizeof(struct Test1) = 8
sizeof(struct Test2) = 8
7. struct
占用的内存大小计算方式
- 第一个成员起始于0偏移处
- 每个成员按其类型大小和
pack
参数中较小的一个进行对齐
偏移地址必须能被对齐参数整除
结构体成员的大小取其内部长度最大的数据成员作为其大小 - 结构体总长度必须为所有对齐参数的整数倍
注意: 编译器在默认情况下按照4字节对齐
#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(1)
struct Test2
{ // 对齐参数 偏移地址 大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 1 2 2
int i; // 1 4 4
};
#pragma pack()
8. 小结
-
#pragma
用于指示编译器完成一些特定的动作 -
#pragma
所定义的很多指示字是编译器特有的 -
#pragma message
:用于自定义编译消息 -
#pragma once
:用于保证头文件只被编译一次 -
#pragma pack
:用于指定内存对齐方式
声明:此文章为本人在学习狄泰软件学院《C语言深度解析》所做的笔记,文章中包含狄泰软件资料内容一切版权归狄泰软件所有!