引数が文字列リテラルかどうかを判断できますか? 質問する

引数が文字列リテラルかどうかを判断できますか? 質問する

マクロまたは関数に渡された引数が文字列リテラルであるかどうかをコンパイル時または実行時に判断することは可能ですか?

例えば、

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

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

または

bool is_string_literal(const char * s);

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

ありがとう。

ベストアンサー1

はい!(ありがとうジェームズ・マクネリスそしてGマン"Hello, " "World!"修正のため。連結前に文字列化されるような連結リテラルを正しく処理するように更新されました。

#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;
}

これにより、引数は関数に渡される前に文字列化されるため、引数が文字列リテラルの場合、関数に渡される引数は引用符で囲まれます。

これを文字列リテラルと考えると次のようになります。

const char *p = "string";
// should is_literal(p) be true or false?

お手伝いできません。実装定義の (または *ゾッとする* 未定義の) 動作を使用して、文字列が読み取り専用メモリに格納されているかどうかをテストできる可能性がありますが、一部の (おそらく古い) システムではp変更される可能性があります。

このような機能の使用に疑問を抱く人は、次の点を考慮してください。

enum string_type { LITERAL, ARRAY, POINTER };

void string_func(/*const? */char *c, enum string_type t);

string_function呼び出しごとに 2 番目の引数を明示的に指定するのではなく、is_literalマクロでラップすることができます。

#define string_func(s) \
    (string_func)(s, is_literal(s)  ? LITERAL :
        (void *)s == (void *)&s ? ARRAY : POINTER)

リテラルが存在しない単純な C の場合や、何らかの理由で ではなく を取る関数を記述したくない、または記述constできない場合を除いて、それがなぜ違いを生むのか想像できません。しかし、何かをしたい理由はいろいろあります。いつかあなたも、ひどいハックに頼る必要があると感じるかもしれません。const char *char

おすすめ記事