Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

math.h macro collisions

Tags:

c++

c++11

g++

glibc

Macro DOMAIN in math.h collides with enums and possibly other types. I don't know what to make of it.

#include <algorithm>

enum Type { DOMAIN };


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

}

Compile with flag -std=c++11. The C99 version of this code compiles perfectly fine though:

#include <algorithm>

enum Type { DOMAIN };


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

}

I checked the source code and the library is to blame. algorithm includes stl_algo.h, in which there is ifdef:

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

The following code compiles fine on c++11 compiler:

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

Is it a feature or a bug?

EDIT* dirty fix:

#ifdef DOMAIN
#undef DOMAIN
#endif
like image 716
Mikel Avatar asked Jul 31 '15 17:07

Mikel


1 Answers

It's a bug (or a "wart" if you want to be generous).

All the rest of this answer refers only to GCC and the Gnu standard C library headers. The man page references are to a linux system (but I've added links to man7.org).

The DOMAIN macro comes from math.h's System V support. (See man matherr.) System V support is normally enabled by defining the _SVID_SOURCE feature-test macro (see man feature_test_macros), but it is enabled along with a raft of other extensions if _GNU_SOURCE is defined, or by default if no feature test macros are defined.

gcc predefines _GNU_SOURCE for C programs if the --std option is omitted or set to gnu##. The various --std=c## options cause __STRICT_ANSI__ to be defined. Consequently, compiling C code with some explicit C standard will suppress the System V extensions. That needs to be done because the System V extensions are not standards-compatible, not even with Posix, because they pollute the global namespace. (DOMAIN is just one example of this pollution.)

However, g++ defines _GNU_SOURCE even if --std=c++## is specified, and consequently the System V extensions will sneak in. (Thanks to @dyp for the link to this libstdc++ FAQ entry. and this long and inconclusive discussion from 2001 on the GCC mailing list)

An ugly workaround is to set up the features yourself, and then undefine __USE_SVID:

#include <features.h>
#undef __USE_SVID

#include <random>
#include <iostream>

int main(){   
    std::cout << DOMAIN << std::endl;
    return 0;
}

(Live on coliru)

IMHO, this should not be necessary. But there it is.

like image 90
rici Avatar answered Sep 24 '22 04:09

rici