1、#pragma的常用参数
(1)#pragma once
1)作用
与#ifndef一样,可以用于防止头文件的重复包含,只不过ifndef方式是最古老、最普遍的方式,所有的C/C++编译器都支持,而#pragma once是一个比较新的方式,有些编译器可能并不支持#pragma once方式。
不过经过多年的发展,现在大多数编译器都支持#pragma once的这种写法了,比如gcc编译器就支持这种写法,所以当你在某些头文件看到了#pragma once的写法时不要蒙圈。
不过目前主流的还是#ifndef方式,不过为了让程序有更好的移植性,我们建议大家还是多使用#ifndef的方式,毕竟编译器对这种方式的支持性更好些。
有些头文件可能会比较奇葩,在文件头上,#pragma once和#ifndef方式都有,编译器支持哪种它就用哪种。
2)#pragma once使用举例
helloworld.h
#pragma once //预编译后,#pragma once就没有了 struct stu { int num; char name[20]; };
helloworld.c
#include <stdio.h> #include "helloworld.h" #include "helloworld.h" //重复include int main(void) { return 0; }
查看预编译的结果:
# 3 "helloworld.h" struct stu //struct stu结构体类型的定义只有一个,说明#pragma once成功的防止了头文件内容的重复。 { int num; char name[20]; }; # 3 "helloworld.c" 2 int main(void) { fun(10); return 0; }
3)#pragma once与#ifndef实现方式的区别
这二者都能实现防止头文件内容重复,只不过在实现原理上有一点区别。
(a)#ifndef
如果helloworld.h使用#ifndef方式来实现的话,两次include的helloworld.h的内容都会被复制到到.c文件中,然后使用#ifndef保留第一次包含内容,然后去掉重复内容。
#ifndef的原理就是,先把所有.h的内容都复制到.c中(包括重复的),然后使用#ifndef来去掉重复的内容。
(b)#pragma once
#pragma once与ifndef有所不同,使用#pragma once方式来实现时,只会复制第一次incldue的.h的
内容到.c中,后续重复inlcude的.h的内容根本不会被复制到.c中,后续重复的inlcude会被直接被判定无效。
从以上介绍可以看出,从效率上来说,#pragma once的效率比#ifndef方式更高,因为使用#ifndef方式时,所有重复include的.h的内容都需要被复制到.c中,但是#pragma once不会。
(2)#pragma auto_inline
这一个与“内联函数”有关,后面在函数章节讲内联函数时,再来介绍。
(3)#pragma message(message string)
1)作用
在编译时打印提示信息,注意我说的是在编译时而不是在预编译时,也就是说#pragma message这话是在第二阶段“编译”时才会起作用的。
2)使用举例
(a)例子1
hellowolrd.c
#include <stdio.h> #ifndef _ARM #pragma message( "macro _ARM not defined" ) #endif int main(void) { return 0; }
查看预编译结果:
# 7 "helloworld.c" #pragma message( "macro _ARM not defined" ) # 7 "helloworld.c" # 11 "helloworld.c" int main(void) { return 0; }
预编译后,#pragma message( "Pentium processor build" ) 还在,说明还没有被处理。
编译:
gcc -S helloworld.i -o hellowolrd.s
输出信息:
helloworld.c:5:9: note: #pragma message: macro _ARM not defined #pragma message( "macro _ARM not defined"
通过以上的这个例子,我们也可以通过#pragma message这种方式,在“编译阶段”提示某个宏有没有被定义,不过我们前面也说过,有关宏的报错,应该尽量在预编译阶段使用#error来报错会更好,至于为什么建议这样,我们前面有介绍过原因。
(b)例子2
hellowolrd.c
#include <stdio.h> #pragma message( "Compiling " __FILE__ ) //提示目前正在编译什么文件 int main(void) { return 0; }
编译:gcc helloworld.c
helloworld.c:3:9: note: #pragma message: Compiling helloworld.c #pragma message( "Compiling " __FILE__ )
通过#pragma message可以在编译时的打印提示信息,有编译过大型c工程的同学估计都知道,在编译的过程中,往往打印很多的编译时的提示信息,告诉你目前编译到什么位置了,目前被编译文件是哪一个,编译状态是怎样的,其实这些信息大多都是#pragma message打印出来的。
通过提示的这些信息,可以向编译者提示编译状态,特别编译开源的官方C源码时,打印提示信息还是很重要的,因为通过这些提示信息,可以帮助排查错误,实现源码的移植。
你将来写大型C工程项目时,你也可以使用#pragma message来打印编译时提示信息。
(4)#pragma pack:内存对齐
后面讲到结构体的内存对齐时,我们再来介绍这个玩意。
(5)bss_seg、data_seg、code_seg、const_seg
1)bss_seg:修改和设置.bss节
2)data_seg:修改和设置.data节
3)const_seg:修改和设置.ro.data节
4)code_seg:修改和设置.text节
这些简单了解即可,因为如果要研究清楚的话,其实内容还比较深,但是就算你研究明白了,对于我们实际开发的意义并不大,因此这里只简单提下。
有关#pragma其它参数,我们这里也是持同样的观点,以后真的当你遇到某种特殊参数时,你再有针对性的去学习,效果会更好。