math.h macro collisions

math.h macro collisions

本文关键字:collisions macro math      更新时间:2023-10-16

math.h中的宏DOMAIN与枚举以及可能的其他类型冲突。我不知道该怎么办。

#include <algorithm>
enum Type { DOMAIN };

int main(){
    Type t = Type::DOMAIN;
    return 0;
}

使用标志-std=c++11编译。这个代码的C99版本编译得非常好:

#include <algorithm>
enum Type { DOMAIN };

int main(){
    Type t = DOMAIN;
    return 0;
}

我检查了源代码,库是罪魁祸首。算法包括stl_algo.h,其中有ifdef:

#if __cplusplus >= 201103L
#include <random>     // for std::uniform_int_distribution 
#include <functional> // for std::bind
#endif

以下代码在c++11编译器上编译良好:

#include <random>
#include <iostream>
int main(){
    std::cout << DOMAIN << std::endl;
    return 0;
}

这是一个功能还是一个bug?

EDIT*脏修复:

#ifdef DOMAIN
#undef DOMAIN
#endif

这是一个bug(如果你想大方一点,也可以是一个"疣"(。

这个答案的其余部分只涉及GCC和Gnu标准的C库头。man页面引用的是linux系统(但我添加了man7.org的链接(

DOMAIN宏来自math.h的System V支持。(请参阅man matherr。(System V支持通常通过定义_SVID_SOURCE功能测试宏来启用(请参见man feature_test_macros(,但如果定义了_GNU_SOURCE,则会与一系列其他扩展一起启用;如果未定义功能测试宏,则默认情况下会启用。

如果--std选项被省略或设置为gnu##,则gcc为C程序预定义_GNU_SOURCE。各种--std=c##选项导致定义__STRICT_ANSI__。因此,使用某些明确的C标准编译C代码将抑制System V扩展。需要这样做是因为System V扩展与标准不兼容,甚至与Posix也不兼容,因为它们污染了全局命名空间。(DOMAIN只是这种污染的一个例子。(

然而,即使指定了--std=c++##g++也定义了_GNU_SOURCE,因此System V扩展将悄悄进入

一个丑陋的解决方法是自己设置功能,然后取消定义__USE_SVID:

#include <features.h>
#undef __USE_SVID
#include <random>
#include <iostream>
int main(){   
    std::cout << DOMAIN << std::endl;
    return 0;
}

(在coliru上直播(

IMHO,这应该没有必要。但它就在那里。

N4140的§17.6.5.2[res.on.headers]/1规定:

C++标头可以包括其他C++标头。C++标头应提供其概要中出现的声明和定义。大纲中显示的C++标头(包括其他C++标头(应提供出现在其他标头概要中的声明和定义。

因此,<algorithm>#include <cmath>将有问题的宏常量注入到您的命名空间中是有效的。

然而,请注意,标准(§17.6.4.3.1[宏名称]/1(不允许您的"快速且肮脏的修复":

包含标准库标头的翻译单元不得在任何标准库标头中声明#define#undef名称。

您必须为enum常量选择一个不同于DOMAIN的名称。