linux gcc 宏定义 __GNUC__ __GNUC_MINOR__ 版本区分

news/2025/1/11 23:34:44/

今天在看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_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__);
#endifreturn 0;
}

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

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 > 30200printf("gcc > 3.2.0\n");//...
#endifreturn 0;
}

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

 

 

 


http://www.ppmy.cn/news/632153.html

相关文章

灰色的果实

灰色的果实 问题描述 树为灰色果实之树&#xff0c;不定时会长出灰色果实。贸然接近果实只会使得自己受其迷惑最后神经错乱而 浑浑噩噩不得终日&#xff0c;与死人无异。你的目标是成功到达树的顶端&#xff0c;砍下灰色果实的灵脉。 为了能够免除灰色果实的影响&#xff0…

告诉你什么是 Java 宏变量,别再疑惑不解了

小编第一次被问到这个概念时&#xff0c;确实是有点懵。入行没多久&#xff0c;莫怪莫怪&#xff01;后来翻阅一些资料和博客&#xff0c;才豁然开朗。 小编认为Java中其实没有关于宏的定义&#xff0c;《Thinking in Java》中我也没有找到相关的介绍。这个概念应该是从C语言中…

恶魔果实

组合题&#xff08;牛客&#xff09;: 恶魔果实. 题目描述 牛牛得到了一堆神奇的恶魔果实&#xff0c;每个恶魔果实都给了牛牛一个改变数字的能力&#xff0c;可以把数字a变成数字b&#xff0c;现在牛牛有一个数字x&#xff0c;他想知道吃完这n个恶魔果实后&#xff0c;他可以…

gcc宏展开

要把源代码中的宏展开&#xff0c;其实只要使用gcc进行预处理即可。 gcc -E source.c >out.txt -E表示只进行预处理&#xff0c;不进行编译。 预处理时会把注释当成空格处理掉&#xff0c;如果想保留其中的注释&#xff0c;可以加上-C选项&#xff0c;即&#xff1a; gc…

将一个宏被另一个宏使用

带参数的宏定义的一般形式如下&#xff1a; #define <宏名>&#xff08;<参数表>&#xff09; <宏体> 一.如下图 我想要计算一个三角形的面积 我要定义两个宏&#xff1a;一个用来表示&#xff1a;s1/2*(abc) 一个用来表示&#xff1a; (s-a)(s-b)*(s-c) …

NLP创业破局,如何摘取更高处的果实

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 2022年&#xff0c;云从科技、商汤科技先后登陆资本市场&#xff0c;计算机视觉四小龙中的旷视科技、依图科技也在摩拳擦掌。反观NLP领域&#xff0c;相关企业的发展速度、融资规模、上市进程仿佛都要略逊一筹&…

windows下cmake找不到glew、glfw等包的解决方法

错误的类型 这里就放一个glfw的错误图吧&#xff0c;glew报错的话和这个是一样的 找不到glew的解决方案 首先去官网下载glew编译好的文件&#xff0c;链接glew 之后解压如图&#xff0c;我们需要做的是复制bin的路径&#xff0c;我的路径为D:\code_study\glew-2.2.0-win32\gl…

cmake 一些有用的宏

一个开源项目&#xff0c;如果想依赖cmake的find_package规则来实现编译的自动查找&#xff0c;主要是<1>头文件路径<2>库名字<3>库路径这三个方面&#xff0c; 有2个办法&#xff1a; &#xff08;1&#xff09; cmake 有个 系统变量 CMAKE_ROOT 通常比如…