Is there a way to use GCC __attribute__((noreturn)

2019-02-09 07:48发布

问题:

In C11, there is the keyword _Noreturn which is a function specifier (like inline is) that indicates the function does not return — it calls exit() or equivalent. There is also a header, <stdnoreturn.h>, the complete definition for which is:

7.23 _Noreturn <stdnoreturn.h>

¶1 The header <stdnoreturn.h> defines the macro

noreturn

which expands to _Noreturn.

In GNU C (GCC), there is an attribute __attribute__((noreturn)) that does essentially the same job. One difference is that __attribute__((noreturn)) can appear before or after the function declarator:

extern __attribute__((noreturn)) void err_error(const char *format, ...);
extern void err_error(const char *format, ...) __attribute__((noreturn));

The problem is that if you include <stdnoreturn.h> in a translation unit (TU), any subsequent uses of __attribute__((noreturn)) get mapped to __attribute__((_Noreturn)) which then causes the compilation to fail because the attribute _Noreturn is not recognized (even though the keyword is recognized as a keyword). That is, as far as I can tell, you cannot use both systems at once.

  • Is there any way around this problem other than either:

    1. a big-bang migration of all code using the attribute to use <stdnoreturn.h>, or
    2. using the less-than-entirely-graceful _Noreturn keyword?

You can detect C11 by testing __STDC_VERSION__ >= 201112L — the value was specified by Technical Corrigendum 1 because the standard accidentally left the value incompletely specified:

__STDC_VERSION__ The integer constant 201ymmL.178)

178) This macro was not specified in ISO/IEC 9899:1990 and was specified as 199409L in ISO/IEC 9899:1990/Amd.1:1995 and as 199901L in ISO/IEC 9899:1999. The intention is that this will remain an integer constant of type long int that is increased with each revision of this International Standard.

This can be used to condition the treatment in any one header file, but if you have a mixture of modified and unmodified (C11 and C99) headers, I seem to be running into intractable problems with <stdnoreturn.h>.

  • Is it worth filing a bug with GCC to request that __attribute__((_Noreturn)) be made into a synonym for __attribute__((noreturn)) — which would resolve the problem.

回答1:

Use __attribute__((__noreturn__)), instead.

All the gcc attributes have a __ version such that you can sanely use them in system headers without polluting the user name space.

Some platform providers also don't seem to be aware of that problem. I recently discovered that for OS X they have the unprotected version in a macro __dead2.

Also you can't detect the C standard version reliably with the __STDC_VERSION__ macro. All the gcc and clang versions that have a "test" version for C11 that claims C11 if called with -std=c11 without completely implementing it fully. The newer versions are almost there, but only almost.



回答2:

This is precisely why the keyword is _Noreturn and not noreturn. Don't include the stdnoreturn.h header, just use:

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#elif defined(__GNUC__)
#define noreturn __attribute__((noreturn))
#else
#define noreturn
#endif


标签: c gcc clang c11