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

Posted

技术标签:

【中文标题】在 f2c.h 文件中定义 min() max() 宏时出错【英文标题】:Error defining min() max() macro in f2c.h file 【发布时间】:2018-08-01 20:45:13 【问题描述】:

编译使用 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 开发环境。任何帮助表示赞赏。

谢谢。

【问题讨论】:

using namespace std; 与代码一起应用到任何位置。 还要确保 #include "f2c.h" 在所有标准标头之后完成。 πάντα ῥεῖ,您是指从 f2c.h 头文件中删除命名空间 std 吗? NathanOliver 就是这样,有趣的是这不是 VS 的问题。 @JeremyStalmer 其他人提到它,但在 C++ 中的 &lt;algorithm&gt; 标头中已经有一个 std::min 和 std::max 函数。您的宏版本干扰了这些声明。最好的办法是删除 C 宏,只使用 std::minstd::max。此外,这也是为什么 using namespace std; 很危险的原因——使用无处不在的 C 宏 minmax,以及 std::minstd::max 函数。 【参考方案1】:

恭喜,您刚刚学会了为什么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

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

'(' 标记之前的预期 unqualified-id

std::( 是语法错误。编译器期望在:: 之后有另一个标识符。原来有一个。但是宏用垃圾替换了那个标识符。因为所有宏所做的只是替换标记而不考虑语法上下文。而且由于宏只是默默地为您重写代码,因此您永远无法看到“实际”编译器看到的代码。当出现问题时,您所看到的只是重写代码产生的错误消息。 (除非你告诉你的编译器请转储出预处理的结果,并筛选你得到的文本海洋。)

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

【讨论】:

以上是关于在 f2c.h 文件中定义 min() max() 宏时出错的主要内容,如果未能解决你的问题,请参考以下文章

如何为空输入(而不是默认的+Inf和-Inf)指定R中Max,Min的自定义返回值?

在 codeigniter 中验证 max_length、min_length

在 postgresql 中使用 MIN, MAX, (SUM/COUNT) 子查询

生成具有给定元素数量和错误级别的已定义 Min、Max、Mean 和 Stdev 的随机数数组

INT_MIN和INT_MAX

关于NOMINMAX这个预处理宏