首页 /  技术专区  /  C 宽屏模式 >

预编译关键字——#pragma

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其它参数,我们这里也是持同样的观点,以后真的当你遇到某种特殊参数时,你再有针对性的去学习,效果会更好。



头像
0/200
图片验证码