What preprocessor condition should I check so as to use __attribute__((const))?

637 views Asked by At

I've gotten a piece of code which applies __attribute__((const)) to some functions. Now, I'd rather not remove it when it's usable, but on the other hand, I do want to be more portable, so - I want to say

#if some condition here
#define ATTRIBUTE(an_attribute)  __attribute__((an_attribute))
#else
#define ATTRIBUTE(an_attribute)  
#endif

void foo(int x) ATTRIBUTE(const)

What should the condition be?

Notes:

  • I know that, with C++17, we have this as a proper C++ attribute; but I can't assume C++17 is used. In fact, let's assume it isn't to make things simple.
  • Extra points if you can also answer the question for __attribute__((pure)).
2

There are 2 answers

1
Florian Weimer On BEST ANSWER

__attribute__ is a GNU extension. Only GNU compilers and compilers that claim to be GNU (such as Clang and ICC) support it. So you can do this:

#ifdef __GNUC__
# define ATTRIBUTE(x) __attribute__ (x)
# else
# define ATTRIBUTE(x)
#endif

const was introduced in GCC 2.5, and pure during GCC 2.96 development, so it does not make sense to test separate for their support: these compiler versions will not be able to compile current C++ code anyway. (__attribute__ itself was introduced with GCC 2.0. I think the C++ front end has always supported it.)

5
chris On

GCC provides these attributes under the standard attribute syntax introduced in C++11:

[[gnu::const]] // or [[gnu::pure]]
void foo(int x);

As of C++17, compilers are required to ignore unknown attributes without it causing an error. In practice, compilers will often warn for unknown attributes (with an option to turn that warning off, of course). From what I've seen on Compiler Explorer and from what I remember, compilers older than C++17 also typically warn as well, once they understand the syntax at all. The main compiler I would further test is MSVC, but Compiler Explorer doesn't go too far back in MSVC versions.

If you already have the macro and don't want to change all its uses, you could work this in:

#define ATTRIBUTE(an_attribute) [[gnu::an_attribute]]

If this is not a reasonable solution, I suspect you would have to check against specific compilers and versions in the condition, unfortunately.