概述
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仅仅代表一条编译消息,不代表程序错误。
3.编程实验
#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("%sn", VERSION);
return 0;
}
编译命令如下:
可见,在编译期间,预处理器处理#pragma message,并输出信息。将上述程序用vc编译器进行编译,结果如下:
bcc32的编译输出如下:
4.#pragma once
#pragma once用于保证头文件只被编译—次
#pragma once是编译器相关的,不—定被支持
这两种方式有什么区别?
左边是通过判断宏是否已经定义的方式保证代码只被嵌入一次,预处理器还是处理了这个文件。而#pragma once 保证只处理这个要包含的文件一次。所有pragma once的效率会高一点。
工程中用的比较多的是ifndef方式,而不是pragma方式,因为并不是所有的编译器都支持pragma once。而ifndef是C语言支持的。
5.实例分析
#pragma once使用分析
global.c
#include <stdio.h>
#include “global.h”
#include “global.h”
int main()
{
printf(“g_value = %dn”, g_value);
return 0;
}
global.h
#pragma once
int g_value = 1;
gcc编译运行结果如下:
注释掉pragma once后,gcc就会报重定义错误。
vc2010编译运行结果如下:
bcc32的编译如下:
可见bcc并不支持pragma once。预处理器不支持的pragma参数,会直接删除pragma once这一行。工程中可以使用以下的解决方案:
这样可以保证只包含一次,又保证效率。在不支持pragma once的编译器中,还有ifndef做保证。在支持pragma once 的编译器中,它就起作用了,保证文件只被包含一次,也只被处理一次。
6.#pragma pack
什么是内存对齐?
不同类型的数据在内存中按照一定的规则排列,而不一定是顺序的一个接一个的排列
#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) = %dn", sizeof(struct Test1));
printf(" sizeof(struct Test2) = %dn", sizeof(struct Test2));
return 0;
}
输出结果:
sizeof(struct Test1) = 12
sizeof(struct Test2) = 8
两个结构体的成员是一样的,顺序不一样,占用的空间大小就不一样,这就是内存对齐的结果。
内存排列的结果:
- 为什么需要内存对齐?
CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是1、2、4、8、16…字节
当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常
#pragma pack用于指定内存对齐方式
8.编程实验
#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) = %dn", sizeof(struct Test1));
printf(" sizeof(struct Test2) = %dn", sizeof(struct Test2));
return 0;
}
输出结果:
sizeof(struct Test1) = 8
sizeof(struct Test2) = 8
9.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()
10. 小结
#pragma用于指示编译器完成一些特定的动作
#pragma所定义的很多指示字是编译器特有的
#pragma message:用于自定义编译消息
#pragma once:用于保证头文件只被编译一次
#pragma pack:用于指定内存对齐方式
————————————————
版权声明:本文为CSDN博主「小虾米_2018」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22847457/article/details/98962495
最后
以上就是大方蚂蚁为你收集整理的复习c语言深度剖析(24)—#pragma使用分析、内存对齐的全部内容,希望文章能够帮你解决复习c语言深度剖析(24)—#pragma使用分析、内存对齐所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复