转载:gcc中预定义的宏__GNUC__ - Cccarl - 博客园 (cnblogs.com)

今天在看Linux系统编程这本书的代码的时候看到了__GNUC__,不太清楚这个宏所以去查了一下,以此记录。GNU C预定义了一系列的宏,这些宏都是以双下划线开始的,这里只讲一下__GNUC__  __GNUC_MINOR__ __GNUC_PATCHLEVEL__,其他GNU C的预定义宏可以到这里查看:

https://gcc.gnu.org/onlinedocs/gcc-5.1.0/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros

__GNUC__ 、__GNUC_MINOR__ 、__GNUC_PATCHLEVEL__分别代表gcc的主版本号,次版本号,修正版本号。这里引用一下上面的官方说明:

__GNUC__

__GNUC_MINOR__

__GNUC_PATCHLEVEL__

These macros are defined by all GNU compilers that use the C preprocessor: C, C++, Objective-C and Fortran. Their values are the major version, minor version, and patch level of the compiler, as integer constants. For example, GCC 3.2.1 will define __GNUC__ to 3, __GNUC_MINOR__ to 2, and __GNUC_PATCHLEVEL__ to 1. These macros are also defined if you invoke the preprocessor directly.

__GNUC_PATCHLEVEL__ is new to GCC 3.0; it is also present in the widely-used development snapshots leading up to 3.0 (which identify themselves as GCC 2.96 or 2.97, depending on which snapshot you have).

If all you need to know is whether or not your program is being compiled by GCC, or a non-GCC compiler that claims to accept the GNU C dialects, you can simply test __GNUC__. If you need to write code which depends on a specific version, you must be more careful. Each time the minor version is increased, the patch level is reset to zero; each time the major version is increased (which happens rarely), the minor version and patch level are reset. If you wish to use the predefined macros directly in the conditional, you will need to write it like this:

          /* Test for GCC > 3.2.0 */
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
(__GNUC_MINOR__ == 2 && \
__GNUC_PATCHLEVEL__ > 0))

Another approach is to use the predefined macros to calculate a single number, then compare that against a threshold:

          #define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
...
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200

Many people find this form easier to understand.

上面这一大段英语实际是在讲:

注意,__GNUC_PATCHLEVEL__是从gcc 3.0以后才有的,在这之前的gcc是没有预定义这个宏的。我们可以用gcc --version来查看自己系统中的gcc版本,现在的gcc版本普遍都是3.0以后了吧,就我的系统而言,是4.9.2,那么对应的__GNUC__就是4,__GNUC_MINOR__就是9,__GNUC_PATCHLEVEL__就是2。这几个宏的类型都是int,被扩展后,会得到整数的字面值。由于是宏,因此我们可以通过只预处理源程序来观察他们的文本值。比如,只对下面这段代码进行预处理,预处理(gcc -E)以后是对宏进行直接的替换,所以我们就能看到这三个宏的文本值:

#include <stdio.h>

int main()
{
#ifdef __GNUC__
printf("__GNUC__ = %d\n",__GNUC__);
#endif
#ifdef __GNUC_MINOR__
printf("__GNUC_MINOR__ = %d\n",__GNUC_MINOR__);
#endif
#ifdef __GNUC_PATCHLEVEL__
printf("__GNUC_PATCHLEVEL__ = %d\n",__GNUC_PATCHLEVEL__);
#endif return 0;
}

预编译以后的文件函数部分:

# 942 "/usr/include/stdio.h" 3 4

# 2 "test.c" 2

int main()
{ printf("__GNUC__ = %d\n",4); printf("__GNUC_MINOR__ = %d\n",9); printf("__GNUC_PATCHLEVEL__ = %d\n",2); return 0;
}

这样就很直观地看到,__GNUC__被替换成了4,__GNUC_MINOR__被替换成了9,__GNUC_PATCHLEVEL__替换成了2。

为什么要预定义了这三个宏呢?这是为了方便我们在针对特定版本的gcc编译器进行代码编写的,比如我们的代码要求gcc的版本至少在3.2.0以上,我们就可以写成如下方式的条件编译:

/* Test for GCC > 3.2.0 */
#if __GNUC__ > 3 || \
  (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
    (__GNUC_MINOR__ == 2 && \
      __GNUC_PATCHLEVEL__ > 0)))
  printf("gcc > 3.2.0\n");
  //...
#endif

注意上面把条件编译#if的条件写成了多行的时候(和宏定义一样,如果宏定义一行写不完,要在最后加一个行继续符'\'),每行最后的行继续符'\'后面不能跟任何符号,空格、制表符等都不行,他表示下一行的也是并列条件(通常为||或&&的右操作数),通常在编译以前会把行继续符'\'以及前面的换行符都去掉,这样就可以看作是同一行的了。

当然有的人觉得上面的条件那么大一串看起来非常不顺眼,理解起来也不容易,这时候我们可以自己定义一个宏GCC_VERSION用来表示gcc版本,原理也很简单就是把主版本号*10000+次版本号*100+修订版本号,最终用这个值来判断gcc的版本号:

#include <stdio.h>
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
int main()
{
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200
printf("gcc > 3.2.0\n");
//...
#endif
return 0;
}

好啦,对__GNUC__这个预定义的宏变量算是有了一个基本的了解,作用是用来针对特定版本的gcc进行编写代码,至于其他预定义的宏呢可以去本文刚开始的时候给出的网站上查看,他们各自的作用也都写的非常清楚。

gcc中预定义的宏__GNUC__的更多相关文章

  1. visual c++中预定义的宏

    一.主要目标 (由于visual studio通常包含很多开发环境,通常将其中c/c++的ide称为visual c++ 20xx) 整理下visual c++ 2010下预定义的宏.做一下备忘和了解 ...

  2. ARM编译器中预定义的宏

    arm系列目前支持三大主流的工具链,realview的armcc,iar ewarm的iccarm,gnu的gcc,编译器在编译的时候会预定义一些宏,这些宏在工程中起到不可或缺的作用. 例如 /* d ...

  3. C++中预定义的宏

    以下信息摘自与标准C++的文档中. 如果把这些宏加在程序的日志中,它将为开发人员进行问题分析提供了很好的帮助. standard c++ 1998版The following macro names ...

  4. C标准中一些预定义的宏

    C标准中指定了一些预定义的宏,对于编程经常会用到.下面这个表中就是一些常常用到的预定义宏. 宏(双下滑线) 意义 __DATE__ 进行预处理的日期(“Mmm dd yyyy”形式的字符串文字) __ ...

  5. C标准中一些预定义的宏,如__FILE__,__func__等

    C标准中一些预定义的宏 C标准中指定了一些预定义的宏,对于编程经常会用到.下面这个表中就是一些常常用到的预定义宏. 宏 意义 __DATE__ 进行预处理的日期(“Mmm dd yyyy”形式的字符串 ...

  6. VS2013 预定义的宏

    Visual Studio 2013 预定义的宏 https://msdn.microsoft.com/zh-cn/library/b0084kay(v=vs.120).aspx 列出预定义的 ANS ...

  7. 2019-8-31-dotnet-新项目格式与对应框架预定义的宏

    title author date CreateTime categories dotnet 新项目格式与对应框架预定义的宏 lindexi 2019-08-31 16:55:58 +0800 201 ...

  8. dotnet 新项目格式与对应框架预定义的宏

    在 sdk style 的项目格式支持使用多框架开发,此时需要在代码里面通过宏判断,在编译的时候执行不同的代码.本文告诉大家在框架里面对应的预定义的条件编译符有哪些 在让一个 csproj 项目指定多 ...

  9. 五个在XML文档中预定义好的实体

    下面是五个在XML文档中预定义好的实体: < < 小于号 > > 大于号 & & 和 &apos; ' 单引号 " " 双引号 实体 ...

随机推荐

  1. vue 工作随笔

    现在工作要做一个电商项目,将工3作的笔记记在这儿,以后方便结总 本套项目用的前端方案 是: vue vue-router Element -ui Axios Echarts 后端技术采用node.js ...

  2. Elaticsearch倒排索引

    ES倒排索引基本原理 索引(index)可以分为正序索引(Forward Indexes)和倒排索引(Inverted Index)两种.在关系型数据库中使用索引可以避免数据检索走全表扫描,将检索的时 ...

  3. Spring框架(第一天)

    一. 引言 a) 什么是Spring框架?(spring官网:www.springsource.org) 3.x  不提供第三发依赖jar 目前已经到了5.x版本. Spring轻量级(代码入侵性小) ...

  4. Shell系列(20)- 字符截取命令cut

    前言 grep是按行提取:cut默认是通过制表符,按列提取,不能识别用空格作为分隔符 语法 cut [选项] [文件] 选项 -f :列号,截取哪几列数据,多个列号用逗号隔开:列与列之间默认用TAB制 ...

  5. mysql 复合索引 为什么遵循最左原则

    1,>mysql :多列索引  https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 1>,B+树: h ...

  6. HTML 网页开发、CSS 基础语法——六. HTML基本结构

    1.基本骨架 HTML文件最基本的四个标签,组成了网页的基本骨架,包括:<html>. <head>.<title>.<body>四组标签. ① < ...

  7. P4640-[BJWC2008]王之财宝【OGF,Lucas定理】

    正题 题目链接:https://www.luogu.com.cn/problem/P4640 题目大意 \(n\)种物品,其中\(t\)种物品是有个数限制的,第\(i\)种限制为\(b_i\),求选出 ...

  8. Python3入门系列之-----函数

    什么是函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己 ...

  9. 什么鬼?你还搞不懂json和字典的区别??

    现在自动化培训烂大街,是个人都能说的上几个框架,面试如果问框架相关问题,求职者只需一瓶 82 年的雪碧,会吹的让你怀疑人生!所以面试官为了更清楚的知道你是停留在表面上的花拳绣腿还是有扎实的基础,就不会 ...

  10. java SE(未完结)

    数据类型与运算符 数据类型 基础数据类型 数值型 正整型 byte short int long 结尾加(l/L) 浮点型 float 结尾加(f/F) double 字符型 char 只能存储一个字 ...