Search code examples
cstatic-assert

static_assert the signedness of wide character literals?


I would like to static_assert() that the signedness of wide character literals (L'x') matches that of wchar_t.

The definition of wchar_t is my own. (I am implementing a C standard library.) I would like to fail early, fail loud if the compiler used by a user has a different idea about wide character signedness than what is configured in the library.

Asserting a matching size of the types is easy:

static_assert( sizeof( wchar_t ) == sizeof( L'x' ), "size matches" );

For the builtin type char, testing the signedness is easy. Assuming there is a _CHAR_IS_SIGNED defined to either 0 or 1 somewhere,

static_assert( ( (char)-1 < 0 ) == _CHAR_IS_SIGNED, "char is signed" );

does the trick.

But wchar_t is not a builtin type...

Is there a way to make this (static) assertion in "pure" C99 or C11, i.e. without relying on a specific compiler's extensions?


Clarification:

I "am" the library. I have to typedef some integer type to wchar_t.

The compiler -- not me -- defines wide character literals to some type. This type is not assigned a name by the compiler, but ideally should be identical to whatever I am using for wchar_t, including signedness (which, AFAICT, is not specified by the standard).

I would like to assert / test the identity of these types in some way. The (type)-1 < 0 check shown for char above does not work, because I cannot name "the type the compiler uses for literals".


Solution

  • You don't even need to check if compiler uses signed or unsigned type for wide char literals.

    You can simply test if a type of wide char literals matches your typedef:

    static_assert(_Generic(L'.', wchar_t : 1, default : 0), "blahblah");
    

    But if you really want to get the type signedness, use something like this:

    static_assert(_Generic(L'.', char : ((char)-1 < 0), signed char : 1, short : 1, int : 1, long : 1, long long : 1, default : 0) == _WIDE_CHAR_IS_SIGNED, "blahblah");
    

    And (as @chux suggested) here is a safer version which forces a compilation error if wide characters type doesn't match any of the standard ones.

    #define T(x) signed x : 1, unsigned x : 0 // Makes the code more readable
    static_assert(_Generic(L'.', char : ((char)-1 < 0), T(char), T(short), T(int), T(long), T(long long)) == _WIDE_CHAR_IS_SIGNED, "blahblah");
    #undef T