cgccstring-literalsstatic-assert

C: Assert that an expression is a string literal


I would like a static assertion to be sure that a given expression is a string literal. I tried this:

#define SAME_TYPES(x, y)                    __builtin_types_compatible_p(typeof(x), typeof(y))
#define IS_ARRAY(x)                         !SAME_TYPES((x), &(x)[0])
#define IS_COMPILE_TIME_STR(x)              IS_ARRAY(x) && #x[0] == '"'
#define ASSERT_COMPILE_TIME_STR(x)          static_assert(IS_COMPILE_TIME_STR(x), "Only static allocated compile time strings are allowed, but got this: " #x)

/*
 * ASSERT_COMPILE_TIME_STR("hey"); <-- this is fine
 * ASSERT_COMPILE_TIME_STR(1234);  <-- this should fail
 */

Unfortunately, ASSERT_COMPILE_TIME_STR does not work, because #x[0] == '"' does not seem to be a compile-time-constant.

Is there some other way to achieve this? It just has to compile with gcc, so any kind of extensions are fine:)

Thanks a lot


Solution

  • C allows consecutive string constants which the compiler combines into a single constant. You can exploit this by attempting to put a string constant in line with the expression in question.

    #define IS_STR_CONT(x) (void)((void)(x),&(""x""))
    

    A few notes about the above:

    The above accepts this with no warning or error:

    IS_STR_CONT("hello");
    

    While generating one or more errors with these:

    IS_STR_CONT(123);
    IS_STR_CONT(0+);
    IS_STR_CONT(+0);
    int i=0;
    IS_STR_CONT((i++,"xxx"));
    IS_STR_CONT(!"abc");
    IS_STR_CONT(4 + "abc");
    IS_STR_CONT(*"abc");
    IS_STR_CONT("ad" == "abc");
    

    This isn't perfect, but should catch most cases.