Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I determine if an argument is string literal?

Is it possible to determine if an argument passed in macro or function is a string literal at compile time or run time?

For example,

#define is_string_literal(X)
...
...   

is_string_literal("hello") == true;
const char * p = "hello";
is_string_literal(p) == false;

or

bool is_string_literal(const char * s);

is_string_literal("hello") == true;
const char * p = "hello";
is_string_literal(p) == false;

Thanks.

like image 507
absurd Avatar asked Apr 17 '11 03:04

absurd


People also ask

How can you tell something is a string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

Is there a difference between a string and a string literal?

A String literal is a String object, but a String object is not necessarily a String literal. And once assigned to a reference variable, it's all but impossible to tell if a given String object is a literal or not. This was marked as a duplicate of something it doesn't duplicate at all.

What is an example of a string literal?

A string literal is a sequence of zero or more characters enclosed within single quotation marks. The following are examples of string literals: 'Hello, world!' 'He said, "Take it or leave it."'


1 Answers

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.

like image 179
Chris Lutz Avatar answered Sep 29 '22 17:09

Chris Lutz