YES! (Thanks to James McNellis and GMan for corrections. Updated to correctly handle concatenated literals like "Hello, " "World!"
which get stringized before concatenation.)
#define is_literal_(x) is_literal_f(#x, sizeof(#x) - 1)
#define is_literal(x) is_literal_(x)
bool is_literal_f(const char *s, size_t l)
{
const char *e = s + l;
if(s[0] == 'L') s++;
if(s[0] != '"') return false;
for(; s != e; s = strchr(s + 1, '"'))
{
if(s == NULL) return false;
s++;
while(isspace(*s)) s++;
if(*s != '"') return false;
}
return true;
}
This will stringify the argument before passing it to the function, so if the argument was a string literal, the argument passed to our function will be surrounded with quote characters.
If you consider this a string literal:
const char *p = "string";
// should is_literal(p) be true or false?
I cannot help you. You might be able to use some implementation-defined (or *shudder* undefined) behavior to test whether or not a string is stored in read-only memory, but on some (probably older) systems p
could be modified.
For those who question the use of such a function, consider:
enum string_type { LITERAL, ARRAY, POINTER };
void string_func(/*const? */char *c, enum string_type t);
Rather than explicitly specifying the second argument to string_function
on every call, is_literal
allows us to wrap it with a macro:
#define string_func(s)
(string_func)(s, is_literal(s) ? LITERAL :
(void *)s == (void *)&s ? ARRAY : POINTER)
I can't imagine why it would make a difference, except in plain C where literals aren't const
and for some reason you don't want to/can't write the function as taking a const char *
instead of a char
. But there are all kinds of reasons to want to do something. Someday you, too may feel the need to resort to a horrible hack.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…