Determine #defined string length at compile time

Viewed 26241

I have a C-program (an Apache module, i.e. the program runs often), which is going to write() a 0-terminated string over a socket, so I need to know its length.

The string is #defined as:

#define POLICY "<?xml version=\"1.0\"?>\n" \
   "<!DOCTYPE cross-domain-policy SYSTEM\n" \
   "\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" \
   "<cross-domain-policy>\n" \
   "<allow-access-from domain=\"*\" to-ports=\"8080\"/>\n" \
   "</cross-domain-policy>\0"

Is there please a way, better than using strlen(POLICY)+1 at the runtime (and thus calculating the length again and again)?

A preprocessor directive, which would allow setting POLICY_LENGTH already at compile time?

5 Answers

Per other answers, sizeof(STRING) gives the length (including the \0 terminator) for string literals. However, it has one downside: if you accidentally pass it a char* pointer expression instead of a string literal, it will return an incorrect value–the pointer size, which will be 4 for 32-bit programs and 8 for 64-bit–as the following program demonstrates:

#include <stdio.h>

#define foo     "foo: we will give the right answer for this string"
char    bar[] = "bar: and give the right answer for this string too";
char   *baz   = "baz: but for this string our answer is quite wrong"; 

#define PRINT_LENGTH(s) printf("LENGTH(%s)=%zu\n", (s), sizeof(s))

int main(int argc, char **argv) {
   PRINT_LENGTH(foo);
   PRINT_LENGTH(bar);
   PRINT_LENGTH(baz);
   return 0;
}

However, if you are using C11 or later, you can use _Generic to write a macro which will refuse to compile if passed something other than a char[] array:

#include <stdio.h>

#define SIZEOF_CHAR_ARRAY(s) (_Generic(&(s), char(*)[sizeof(s)]: sizeof(s)))

#define foo     "foo: we will give the right answer for this string"
char    bar[] = "bar: and give the right answer for this string too";
char   *baz   = "baz: but for this string our answer is quite wrong"; 

#define PRINT_LENGTH(s) printf("LENGTH(%s)=%zu\n", (s), SIZEOF_CHAR_ARRAY(s))

int main(int argc, char **argv) {
    PRINT_LENGTH(foo);
    PRINT_LENGTH(bar);
    // Will fail to compile if you uncomment incorrect next line:
    // PRINT_LENGTH(baz);
    return 0;
}

Note this doesn't only work for string literals – it also works correctly for mutable arrays, provided they are actual char[] arrays of fixed length as a string literal is.

As written, the above SIZEOF_CHAR_ARRAY macro will fail for const expressions (although you'd think string literals ought to be const, for backward compatibility reasons they are not):

const char quux[] = "quux is const";
// Next line will fail to compile:
PRINT_LENGTH(quux);

However, we can improve our SIZEOF_CHAR_ARRAY macro so the above example will also work:

#define SIZEOF_CHAR_ARRAY(s) (_Generic(&(s), \
    char(*)[sizeof(s)]: sizeof(s), \
    const char(*)[sizeof(s)]: sizeof(s) \
))
Related