90

I am working on a project that has been built with both gcc and msvc so far. We recently started building with clang as well.

There are some parts in the code, where platform-specific things are done:

#ifndef _WIN32
// ignore this in msvc
#endif

Since gcc has previously been the only non-windows build, this was equivalent to saying "do this only for gcc". But now it means "do this only for gcc and clang".

However there are still situations, where I would like to handle something specifically for gcc, and not for clang. Is there a simple and robust way to detect gcc, i.e.

#ifdef ???
// do this *only* for gcc
#endif
ValarDohaeris
  • 6,064
  • 5
  • 31
  • 43

3 Answers3

123
__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__

These macros are defined by all GNU compilers that use the C preprocessor: C, C++, Objective-C and Fortran. Their values are the major version, minor version, and patch level of the compiler, as integer constants. For example, GCC 3.2.1 will define __GNUC__ to 3, __GNUC_MINOR__ to 2, and __GNUC_PATCHLEVEL__ to 1. These macros are also defined if you invoke the preprocessor directly.

Also:

__GNUG__

The GNU C++ compiler defines this. Testing it is equivalent to testing (__GNUC__ && __cplusplus).

Source

Apparently, clang uses them too. However it also defines:

__clang__
__clang_major__
__clang_minor__
__clang_patchlevel__

So you can do:

#ifdef __GNUC__
    #ifndef __clang__
...

Or even better (note the order):

#if defined(__clang__)
....
#elif defined(__GNUC__) || defined(__GNUG__)
....
#elif defined(_MSC_VER)
....
dmg
  • 7,438
  • 2
  • 24
  • 33
  • 8
    These things are all collected in the much more robust [Boost.Predef](http://www.boost.org/doc/libs/release/libs/predef/doc/html/index.html), and the (now outdated) original wiki that sprung that Boost library is located [here](http://sourceforge.net/p/predef/wiki/Compilers/). Note that the Intel compiler will define `__GNUC__` or `_MSC_VER` on the relevant platforms as well. – rubenvb Jan 27 '15 at 09:18
  • 3
    All compilers that support the GNU C set of language extensions define those macros, right down to `__GNUC_PATCHLEVEL__`. So to detect support for a specific GNU C feature on any compiler, you check those macros. On gcc itself, they also map to the actual version of the compiler you're using, but they're best used to tell you what version of the GNU C language is supported, more than the compiler type / version. – Peter Cordes Dec 18 '16 at 05:33
  • This does not seem to work when using clang-cl. In this case `__clang__` and `_MSC_VER` is defined. – Knitschi Apr 08 '21 at 09:00
  • `__clang__`, `__clang_major__`, `__clang_minor__` and `__clang_patchlevel__` are all defined on gcc. What kind of sadistic maniac would design it that way? – Badasahog Jul 15 '22 at 16:07
  • @Badasahog Pardon ? Clang emulates either GCC or MSVC, not the other way around! – Johan Boulé Aug 05 '22 at 21:25
  • @JohanBoulé they both emulate each other – Badasahog Aug 07 '22 at 10:21
  • @Badasahog I insist that GCC does NOT define `__clang__`. Where did you see that happen ? – Johan Boulé Aug 08 '22 at 11:55
  • @JohanBoulé I tested it myself – Badasahog Aug 08 '22 at 12:16
  • @Badasahog The only explanation is you had a glitch in you test. Again, GCC does not define `__clang__`, so the compiler that you tested was either really Clang or something else than GCC. – Johan Boulé Aug 10 '22 at 17:39
  • When `GNUG` is equivalent to `GNUC && cpp` then it's useless to test for both: `GNUC || GNUG` <=> `GNUC || GNUC && cpp` <=> `GNUC && (1 || cpp)` <=> `GNUC`... – Aconcagua Dec 21 '22 at 09:57
14

I use this define:

#define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__))

And test with it:

#if GCC_COMPILER
...
#endif
khaledev
  • 496
  • 4
  • 6
11

With Boost, this becomes very simple:

#include <boost/predef.h>

#if BOOST_COMP_GNUC
// do this *only* for gcc
#endif

See also the Using the predefs section of the boost documentation.

(credit to rubenvb who mentioned this in a comment, to Alberto M for adding the include, and to Frederik Aalund for correcting #ifdef to #if)

Ave Milia
  • 599
  • 4
  • 12
ValarDohaeris
  • 6,064
  • 5
  • 31
  • 43
  • The header to include to get the symbol is ``. – Alberto M Mar 29 '17 at 12:48
  • 2
    You're supposed to use `#if BOOST_COMP_GNUC` and *not* `#ifdef` since the macro is *always* defined (but may be zero). See http://www.boost.org/doc/libs/1_66_0/doc/html/predef/using_the_predefs.html – Frederik Aalund Jan 18 '18 at 12:50
  • Yes, thanks for pointing it out, I thought I tested this when I first posted the answer, but it looks like `#ifdef` probably never worked, at least not for boost versions 1.55 or later. – ValarDohaeris Jan 31 '18 at 09:59
  • 3
    Note that using Boost isn't always the correct solution. Boost can be handy, indeed, but thanks to its size and complexity, can add a large amount of overhead.# – SimonC Jun 13 '19 at 06:43