The requirement is to define a macro which takes a single argument with the following contraints:that is a string literal.
- Is a character pointer
- Must be non-null
- Must be immutable
- Must be 0-terminated
The requirement is to define a macro which takes a single argument with the following contraints:
- Is a character pointer
- Must be non-null
- Must be immutable
- Must be 0-terminated
The requirement is to define a macro which takes a single argument that is a string literal.
Note: I am looking for a solution that would work with at least C99.
Note: I am looking for a solution that would work with at least C99.
C - Force a macro argument to be a string literal
The requirement is to define a macro which takes a single argument with the following contraints:
- Is a character pointer
- Must be non-null
- Must be immutable
- Must be 0-terminated
My first try at it was to surround it with empty string literals (I got this from Modern C):
#define SV(str) (sizeof("" str "") - 1)
Now if I do:
int main(void)
{
static const char *const s = "hello";
char word[] = "hello";
double a = 0.0f;
double *d = &a;
printf("%zu\n", SV(NULL));
printf("%zu\n", SV(word));
printf("%zu\n", SV(d));
printf("%zu\n", SV(s));
return 0;
}
It fails to compile, which was the expected behavior:
macro_str.c: In function ‘main’:
macro_str.c:4:33: error: called object is not a function or function pointer
4 | #define SV(str) (sizeof("" str "") - 1)
| ^~
macro_str.c:19:21: note: in expansion of macro ‘SV’
19 | printf("%zu\n", SV(NULL));
| ^~
macro_str.c:4:40: error: expected ‘)’ before string constant
4 | #define SV(str) (sizeof("" str "") - 1)
| ~ ^~
macro_str.c:19:21: note: in expansion of macro ‘SV’
19 | printf("%zu\n", SV(NULL));
| ^~
macro_str.c:20:24: error: expected ‘)’ before ‘word’
20 | printf("%zu\n", SV(word));
| ^~~~
macro_str.c:4:36: note: in definition of macro ‘SV’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^~~
macro_str.c:4:32: note: to match this ‘(’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^
macro_str.c:20:21: note: in expansion of macro ‘SV’
20 | printf("%zu\n", SV(word));
| ^~
macro_str.c:21:24: error: expected ‘)’ before ‘d’
21 | printf("%zu\n", SV(d));
| ^
macro_str.c:4:36: note: in definition of macro ‘SV’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^~~
macro_str.c:4:32: note: to match this ‘(’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^
macro_str.c:21:21: note: in expansion of macro ‘SV’
21 | printf("%zu\n", SV(d));
| ^~
macro_str.c:22:24: error: expected ‘)’ before ‘s’
22 | printf("%zu\n", SV(s));
| ^
macro_str.c:4:36: note: in definition of macro ‘SV’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^~~
macro_str.c:4:32: note: to match this ‘(’
4 | #define SV(str) (sizeof("" str "") - 1)
| ^
macro_str.c:22:21: note: in expansion of macro ‘SV’
22 | printf("%zu\n", SV(s));
| ^~
make: *** [<builtin>: macro_str] Error 1
Then I proceeded to ask a question on StackOverflow and found instances where this would fail:
SV()
SV(/*comment*/)
SV(-)
SV("abc" - "def")
So I added some more expressions , suggested by @n. m. could be an AI, to it:
#define SV(str) ("" str "", (str)[0], sizeof(str) - 1)
Now it fails for these 4 edge-cases as well. Yet there are still things like:
// I believe the second one is defined-behavior.
SV("abcd" - sizeof "e");
SV("abcd" + sizeof "e");
for which it would compile cleanly. Whilst I am satisfied with the final macro and it serves my use-case, I believe there might still be some improvements it could use.
How can it be made more robust?