GCC 预处理的宏 (predefined macros)

关于宏(macro) 在很早很早就知道, 但是只限于能看懂,在自己编程中从未使用。但是,在Powe8上将GATK HaplotypeCaller的GPU实现和SIMD实行并行处理的时候,遇到了很大的问题。找不到 g_compute_full_float() 函数的定义,因此开始觉得要认真整理一下思路。

1. 首先,编译器已经预定义了一些宏。

2.编译器自己预定一定的宏,在不同的参数下显示结构不同。 power8 上 有-mcpu=power8 的结果不同。

 

如何找到编译器预定义的宏 (predefined macros)

没有专门的头文件定义(或许在编译器的源程序中,但是我们一般不会去查源文件)。常用命令找出所有的predefined macros.

1. 在使用gcc/g++编译器时,可以通过以下命令打印出编译器预编译的宏。

gcc -dM -E - < /dev/null  

or:

You can also do "cpp -dM </dev/null", which invokes preprocessor directly.  【cpp是GPP的Preprocessor】

 

(1) gcc exists on systems where /dev/null means nothing

(2) By default, gcc -dM will read its input file from standard input and write to standard output. Since you're not trying to preprocess any input, you can pass it the empty input using /dev/nul

(3) Note that some preprocessor defines are dependent on command line options - you can test these by adding the relevant options to the above command line. For example, "gcc -dM -E - < /dev/null"   and  "gcc -dM -E -mcpu=power8 - < /dev/null" are not the same. 

 

下面完全不知道在说啥,应该是和C++11有关的,额。

******************************************************************************************************* 

The simple approach (gcc -dM -E - < /dev/null) works fine for gcc but fails for g++. Recently I required a test for a C++11/C++14 feature. Recommendations for their corresponding macro names are published at https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations. But:

g++ -dM -E - < /dev/null | fgrep __cpp_alias_templates

always fails, because it silently invokes the C-drivers (as if invoked by gcc). You can see this by comparing its output against that of gcc or by adding a g++-specific command line option like (-std=c++11) which emits the error message cc1: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C.

Because (the non C++) gcc will never support "Templates Aliases" (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf) you must add the -x c++ option to force the invocation of the C++ compiler (Credits for using the -x c++ options instead of an empty dummy file go to yuyichao, see below):

g++ -dM -E -x c++ /dev/null | fgrep __cpp_alias_templates

There will be no output because g++ (revision 4.9.1, defaults to -std=gnu++98) does not enable C++11-features by default. To do so, use

g++ -dM -E -x c++ -std=c++11 /dev/null | fgrep __cpp_alias_templates

which finally yields

#define __cpp_alias_templates 200704

noting that g++ 4.9.1 does support "Templates Aliases" when invoked with -std=c++11.

**************************************************************************************************

2. 在VS IDE中,可以参看http://msdn.microsoft.com/zh-cn/library/b0084kay

 

 

用户自定义宏

(1)在代码中通过#define自定义宏外,

(2)还可以在编译源文件的时候通过配置编译器实现.

1. 在使用gcc/g++编译器时,通过添加 -D 选项,添加用户自定义的宏。

例如: g++ -o test -D USERM test.cpp

这样就在预处理test.cpp之前,添加了 USERM这个宏定义。

2. 在VS IDE中,可以点击项目的properties页面,选择C++页选项,点击preprocessor,在右边的preProcessor Definitions中添加用户自己的宏,

同样,也会在project预处理之前添加自定义的宏。

 

 

ANSI C标准中有几个标准预定义宏(也是常用的):

  • __LINE__:在源代码中插入当前源代码行号;
  • __FILE__:在源文件中插入当前源文件名;
  • __DATE__:在源文件中插入当前的编译日期
  • __TIME__:在源文件中插入当前编译时间;
  • __STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
  • __cplusplus:当编写C++程序时该标识符被定义。

 

行连接符\

当宏定义一行代码无法写完时, 可以使用反斜杠\续行.即在每行宏后面添加\.

预处理器会把以\结束的宏指令的末尾的\和换行符删除掉,把若干宏指令行合并成一行.

 

gcc生成预处理后文件

gcc/g++可以通过命令参数输出预处理后的文件.

对于C预处理后的文件后缀是.i, c++处理后文件后缀是.ii

命令如下:

1
2
3
g++ -E main.cpp //对main.cpp预处理后结果输出到标准stdout
g++ -c -save-temps main.cpp //生成预处理后main.ii文件
gcc -c -save-temps main.c //生成预处理后main.i文件

生成的.i/.ii文件会原来的cpp文件大很多, 因为把头文件的信息都完整包含进来了.
并且源代码中的宏定义都被处理了, 在预处理后文件中都不见了.

 

 

避免头文件多次被引用

C/C++中的宏最常用的就是通过#ifdef, #endif来避免头文件多次被引用(redefinition).

C++ 03标准中有一条ODR(One Definition Rule)准则, 里面提到:

In any translation unit, a template, type, function, or object can have no more than one definition. Some of these can have any number of declarations. A definition provides an instance.

就是说C++中的模版,类型, 函数, 对象可以有多个声明, 但最多有1个定义.

如果违反ODR原则, 编译器会提示redefinition错误.

如果防止头文件中的定义被多次包含呢? 答案就是宏定义.

对每个头文件都定义一个独特唯一标识的宏,通过判断该宏是否被定义, 而决定是否包含该头文件.

标准模版如下:

1
2
3
4
5
6
7
//头文件name.h
#ifndef NAME_H
#def NAME_H

... //name.h文件定义的内存

#endif

一般来说, 对于头文件定义的宏, 命名规则通常为NAME_H, 其中NAME为头文件名字的大写.

 

高山仰止,景行行止。虽不能至,然心向往之。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值