Search code examples
c++cstatic-assert

static_assert usage in C++ vs C


This is a part of a huge project, so I post an excerpt from a cc file (only one static_assert is needed in the real code, I just experimented with it):

namespace large
{

static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");  // A

namespace fake_n
{
  static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");  // B
}

class fake_c
{
  static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");  // C
};

void fake_f()
{
  static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");  // D
}

}  // namespace large

gcc9 reports the following errors (correspondingly in A,B,C,D cases):

A,B : error: expected constructor, destructor, or type conversion before '(' token

C : error: expected identifier before 'sizeof'
  : error: expected ',' or '...' before 'sizeof'
  : error: ISO C++ forbids declaration of '_Static_assert' with no type [-fpermissive]

D : error: '_Static_assert' was not declared in this scope; did you mean 'static_assert'?

The last error made me think that the problem is with <assert.h> included somehow (through a long chain of includes). I found it and removed "#include <assert.h>", after that all errors are gone.

Questions:

  1. What's the meaning of erros in cases A,B,C ?
  2. Most important: how to handle in general situation with mixing C and C++ files? What if I can not remove (or even find) the corresponding <assert.h> ? How can I tell compiler to use C++ version of static_assert, not C macro?

Thank you!


Solution

    1. Something in one of your headers appears to be doing #define static_assert _Static_assert, which fails in C++ because _Static_assert is a (reserved) identifier with no special meaning; in particular it doesn't perform a static assertion. I get the same errors in an example by manually adding #define static_assert _Static_assert, and similar ones if I do #define static_assert foobar.

      This macro should be in <assert.h> when compiling as C, but a properly written <assert.h> should wrap it in #ifndef __cplusplus so that it doesn't apply to C++ sources. So I suspect either:

      • Your system's <assert.h> is broken

      • Your compiler is confused about what language it's compiling (unlikely because then namespace etc would also be syntax errors)

      • Something else in your tangle of headers (or command-line compilation options) is being naughty and causing #undef __cplusplus or something like that. If you've found the place where <assert.h> is included, you could try and track down the issue with strategic insertions of

    #ifndef __cplusplus
    #error Aargh
    #endif
    
    1. Normally you shouldn't have to do anything. Properly written system headers will support C++ via appropriate #ifdefs, and work correctly when included into C++ programs.

      If you have a header from some third-party library that is written as C only and doesn't support C++, then you have some work to do to adapt it (or complain to its vendors). That's a project beyond the scope of this answer. Wrapping everything in extern "C" is a start but only a start.