在f2c.h文件中定义min()max()宏时出错

时间:2018-08-01 20:45:14

标签: c++ linux macros g++

编译一个利用f2c.h头文件的基于C ++的项目,该头文件中的min和max宏定义如下所示...

#ifndef min
#define min(a,b) ((a) <= (b) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) ((a) >= (b) ? (a) : (b))
#endif

当我使用Microsoft Visual Studio在Windows上编译并运行时,此代码没有问题。现在,我尝试使用g ++编译器进行编译并在LINUX上运行,并且收到以下错误消息...

In file included from tsdriver.cpp:68:0:
/usr/include/c++/6/bits/fstream.tcc: In member function ‘virtual 
std::basic_filebuf<_CharT, _Traits>::int_type std::basic_filebuf<_CharT, 
_Traits>::underflow()’:
f2c.h:155:18: error: expected unqualified-id before ‘(’ token
#define min(a,b) ((a) <= (b) ? (a) : (b))

现在,它只给我有关min宏的错误消息,但是我认为这是由于编译器错误所致,因此必须终止编译。

我已经进行了一些测试,发现可以从一个小的test.cpp程序中调用min / max,而没有任何额外的包含,因此最初认为错误是来自重新定义的,但这没关系,因为#ifndef会防止这种情况?

我不确定如何解决这个问题,并且我仍在适应LINUX开发环境。任何帮助表示赞赏。

谢谢。

1 个答案:

答案 0 :(得分:2)

恭喜,您刚刚了解了macros are evil的使用方法;)宏的问题在于,它们实际上不仅仅只是一种自动文本替换机制,它可以在“实际”编译器获取代码之前更改源代码。看见。它们一般不尊重诸如名称空间或范围之类的东西,因为它们在甚至还不存在这些概念的级别上运行。 C ++从C继承了宏。但是,有了constexprinline和模板,C ++可以更好地解决大多数您通常在C中使用宏的问题。尽管可以说有一些对于C ++中宏的合法用例,通常最好避免使用宏。

那么用g ++编译代码时发生了什么?好吧,fstream.tcc的第396行是您正在使用的标准库实现的一部分,如下所示:

__ilen = std::min(__avail, __buflen);

您很可能包含了一部分标准库,而该库间接包含了fstream.tcc。您很可能在标头中包含了宏定义

#define max(a,b) ((a) >= (b) ? (a) : (b))

,包括该标准标头。这意味着当编译器通过fstream.tcc时,您已经将max定义为类似于函数的宏。因此,编译器将相应地替换所有与max (,)匹配的令牌序列。这意味着代替

__ilen = std::min(__avail, __buflen);

您的标准标题突然显示为:

__ilen = std::((__avail) >= (__buflen) ? (__avail) : (__buflen))(__avail, __buflen);
//            ^--- note this part

这也解释了奇怪的错误消息:

  

在'('令牌之前

std::(是语法错误。编译器期望::之后的另一个标识符。最初只有一个。但是宏将该标识符替换为垃圾。因为所有宏都在不考虑语法上下文的情况下替换了令牌。而且由于宏只是为您静默地重写代码,因此您永远也看不到“实际”编译器看到的代码。当出现问题时,您将看到的是重写的代码所产生的错误消息。 (除非您告诉编译器,请转储预处理结果,然后在结果文本中进行筛选。)

解决此问题的最佳方法:摆脱宏,而仅使用std::min()std::max。如果这样做不那么容易,至少应该至少可以将这些宏转换为内联函数。