C++ 我可以确定参数是否为字符串文字吗?
是否可以确定在宏或函数中传递的参数在编译时或运行时是字符串文字 比如说,C++ 我可以确定参数是否为字符串文字吗?,c++,c,macros,c-preprocessor,C++,C,Macros,C Preprocessor,是否可以确定在宏或函数中传递的参数在编译时或运行时是字符串文字 比如说, #define is_string_literal(X) ... ... is_string_literal("hello") == true; const char * p = "hello"; is_string_literal(p) == false; 或 谢谢。不。字符串文字只是char(在C++中)或const char(在C++中)的数组 您无法区分字符串文字和其他类似的char数组(在C++中):
#define is_string_literal(X)
...
...
is_string_literal("hello") == true;
const char * p = "hello";
is_string_literal(p) == false;
或
谢谢。不。字符串文字只是
char
(在C++中)或const char
(在C++中)的数组
您无法区分字符串文字和其他类似的char
数组(在C++中):
对!!(感谢和更正。已更新以正确处理连接的文本,如“Hello”,“World!”
,这些文本在连接之前被字符串化。)
这将在将参数传递给函数之前对其进行字符串化,因此,如果参数是字符串文字,则传递给函数的参数将被引号字符包围
如果你认为这是字符串文字:
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\u函数
指定第二个参数,is\u literal
允许我们用宏来包装它:
#define string_func(s) \
(string_func)(s, is_literal(s) ? LITERAL :
(void *)s == (void *)&s ? ARRAY : POINTER)
我无法想象它为什么会有不同,除了在普通C中,文本不是const
,并且出于某种原因,您不想/不能将函数编写为使用const char*
而不是char
。但是有各种各样的理由想做点什么。总有一天,你也会觉得需要求助于一种可怕的黑客手段。试试这个:
#define is_string_literal(s) \
(memcmp(#s, "\"", 1) == 0)
根据C/C++变量命名约定,变量名必须以“\”或字母开头 在编译时知道(如问题中所述),使用以下技术。您可以确定给定参数的值是否为字符串文字。如果它是某种数组或指针,比如constcharx[],*p
;然后它将抛出编译器错误
#define is_string_literal(X) _is_string_literal("" X)
bool _is_string_literal (const char *str) { return true; } // practically not needed
[注:我之前的答案被专家否决,但编辑后还未被接受或否决。我正在提交另一个内容相同的答案。]我有一个类似的问题:我想说的是
MY_MACRO("compile-time string")
是合法的,而且
char buffer[200]="a string";
MY_MACRO(buffer)
是合法的,但不允许
MY_MACRO(szArbitraryDynamicString)
我使用GCC的“SyuBug”类型,兼容了MyVC的“μ”,它似乎正确地工作,牺牲了短字符串文字。
< P>因为C++中的字符串文字可以有不同的前缀,那么没有必要检查开始引用:
最好检查结束报价:
- C++11
- msvc2015u3,gcc5.4,clang3.8.0
#include <type_traits>
#define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value
// hint: operator* applies to character literals, but not to double-quoted literals
#define UTILITY_LITERAL_CHAR_(c_str, char_type) UTILITY_CONST_EXPR_VALUE(((void)(c_str * 0), ::utility::literal_char_caster<typename ::utility::remove_cvref<char_type>::type>::cast_from(c_str, L ## c_str, u ## c_str, U ## c_str)))
#define UTILITY_LITERAL_CHAR(c_str, char_type) UTILITY_LITERAL_CHAR_(c_str, char_type)
#define UTILITY_IS_LITERAL_STRING(c_str) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == UTILITY_LITERAL_CHAR('\"', decltype(c_str[0])) : false)
#define UTILITY_IS_LITERAL_STRING_A(c_str) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == '\"' : false)
#define UTILITY_IS_LITERAL_STRING_WITH_PREFIX(c_str, prefix) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == prefix ## '\"' : false)
namespace utility {
template <typename T, T v>
struct const_expr_value
{
static constexpr const T value = v;
};
// remove_reference + remove_cv
template <typename T>
struct remove_cvref
{
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
//// literal_char_caster, literal_string_caster
// template class to replace partial function specialization and avoid overload over different return types
template <typename CharT>
struct literal_char_caster;
template <>
struct literal_char_caster<char>
{
static inline constexpr char
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return ach;
}
};
template <>
struct literal_char_caster<wchar_t>
{
static inline constexpr wchar_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return wch;
}
};
template <>
struct literal_char_caster<char16_t>
{
static inline constexpr char16_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return char16ch;
}
};
template <>
struct literal_char_caster<char32_t>
{
static inline constexpr char32_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return char32ch;
}
};
}
const char * a = "123";
const char b[] = "345";
int main()
{
static_assert(UTILITY_IS_LITERAL_STRING_A(a) == 0, "Aa");
static_assert(UTILITY_IS_LITERAL_STRING(a) == 0, "a");
static_assert(UTILITY_IS_LITERAL_STRING_A(b) == 0, "Ab");
static_assert(UTILITY_IS_LITERAL_STRING(b) == 0, "b");
static_assert(UTILITY_IS_LITERAL_STRING_A("123") == 1, "A123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(L"123", L) == 1, "L123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(u"123", u) == 1, "u123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(U"123", U) == 1, "U123");
static_assert(UTILITY_IS_LITERAL_STRING("123") == 1, "123");
static_assert(UTILITY_IS_LITERAL_STRING(L"123") == 1, "L123");
static_assert(UTILITY_IS_LITERAL_STRING(u"123") == 1, "u123");
static_assert(UTILITY_IS_LITERAL_STRING(U"123") == 1, "U123");
}
#包括
#定义实用工具常量表达式值(exp)::实用工具::常量表达式值::值
//提示:运算符*适用于字符文字,但不适用于双引号文字
#定义实用工具文字字符(c#str,CHAR#u type)实用工具常量表达式值(((void)(c#str*0),::实用工具::文字字符caster::cast#from(c#str,L#c#str,u#c#str,u#c#str,u#c#str)
#定义实用工具文字字符(c_str,字符类型)实用工具文字字符(c_str,字符类型)
#定义实用工具是文字字符串(c#u str)实用工具常量表达式值((sizeof(#c#u str)>1)?c#str[sizeof(#c#str)-2]==实用工具文字字符('\'),decltype(c#u str[0]):false)
#定义实用程序是文字字符串实用程序常量表达式值((sizeof(#c#u str)>1)?c#u str[sizeof(#c#u str)-2]=='\':false)
#定义实用程序是带有前缀(c#str,PREFIX)的文字字符串实用程序常量EXPR值((sizeof(#c#str)>1)?c#str[sizeof(#c#str)-2]==前缀(false)
命名空间实用程序{
模板
结构常数表达式值
{
静态constexpr const T值=v;
};
//删除参考+删除cv
模板
结构删除\u cvref
{
使用type=typename std::remove_cv::type;
};
////文字字符施法器,文字字符串施法器
//模板类来替换部分函数专门化,并避免不同返回类型的重载
模板
struct literal\u char\u caster;
模板
结构文字字符施法器
{
静态内联constexpr字符
投出(
查拉赫,
wchar_t wch,
第16章第16章,
第32章(第32章)
{
返回ach;
}
};
模板
结构文字字符施法器
{
静态内联constexpr wchar\t
投出(
查拉赫,
wchar_t wch,
第16章第16章,
第32章(第32章)
{
返回wch;
}
};
模板
结构文字字符施法器
{
静态内联constexpr char16\u t
投出(
查拉赫,
wchar_t wch,
第16章第16章,
第32章(第32章)
{
返回字符16ch;
}
};
模板
结构文字字符施法器
{
静态内联constexpr char32\u t
投出(
查拉赫,
wchar_t wch,
第16章第16章,
第32章(第32章)
{
返回char32ch;
}
};
}
常量字符*a=“123”;
常量字符b[]=“345”;
int main()
{
静态断言(实用程序是文本字符串A(A)==0,“Aa”);
静态断言(实用工具是文本字符串(a)==0,“a”);
静态断言(实用工具是文本字符串A(b)==0,“Ab”);
静态断言(实用工具是文本字符串(b)==0,“b”);
静态断言(实用程序是文本字符串A(“123”)==1,“A123”);
静态断言(实用程序是带有前缀(L“123”,L)=1,“L123”)的文本字符串);
静态断言(实用工具是带有前缀(u“123”,u)=1,“u123”)的文本字符串);
静态断言(实用工具是带有前缀(U“123”,U)=1,“U123”)的文本字符串);
char buffer[200]="a string";
MY_MACRO(buffer)
MY_MACRO(szArbitraryDynamicString)
#include <type_traits>
#define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value
// hint: operator* applies to character literals, but not to double-quoted literals
#define UTILITY_LITERAL_CHAR_(c_str, char_type) UTILITY_CONST_EXPR_VALUE(((void)(c_str * 0), ::utility::literal_char_caster<typename ::utility::remove_cvref<char_type>::type>::cast_from(c_str, L ## c_str, u ## c_str, U ## c_str)))
#define UTILITY_LITERAL_CHAR(c_str, char_type) UTILITY_LITERAL_CHAR_(c_str, char_type)
#define UTILITY_IS_LITERAL_STRING(c_str) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == UTILITY_LITERAL_CHAR('\"', decltype(c_str[0])) : false)
#define UTILITY_IS_LITERAL_STRING_A(c_str) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == '\"' : false)
#define UTILITY_IS_LITERAL_STRING_WITH_PREFIX(c_str, prefix) UTILITY_CONST_EXPR_VALUE((sizeof(#c_str) > 1) ? #c_str [sizeof(#c_str) - 2] == prefix ## '\"' : false)
namespace utility {
template <typename T, T v>
struct const_expr_value
{
static constexpr const T value = v;
};
// remove_reference + remove_cv
template <typename T>
struct remove_cvref
{
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
//// literal_char_caster, literal_string_caster
// template class to replace partial function specialization and avoid overload over different return types
template <typename CharT>
struct literal_char_caster;
template <>
struct literal_char_caster<char>
{
static inline constexpr char
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return ach;
}
};
template <>
struct literal_char_caster<wchar_t>
{
static inline constexpr wchar_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return wch;
}
};
template <>
struct literal_char_caster<char16_t>
{
static inline constexpr char16_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return char16ch;
}
};
template <>
struct literal_char_caster<char32_t>
{
static inline constexpr char32_t
cast_from(
char ach,
wchar_t wch,
char16_t char16ch,
char32_t char32ch)
{
return char32ch;
}
};
}
const char * a = "123";
const char b[] = "345";
int main()
{
static_assert(UTILITY_IS_LITERAL_STRING_A(a) == 0, "Aa");
static_assert(UTILITY_IS_LITERAL_STRING(a) == 0, "a");
static_assert(UTILITY_IS_LITERAL_STRING_A(b) == 0, "Ab");
static_assert(UTILITY_IS_LITERAL_STRING(b) == 0, "b");
static_assert(UTILITY_IS_LITERAL_STRING_A("123") == 1, "A123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(L"123", L) == 1, "L123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(u"123", u) == 1, "u123");
static_assert(UTILITY_IS_LITERAL_STRING_WITH_PREFIX(U"123", U) == 1, "U123");
static_assert(UTILITY_IS_LITERAL_STRING("123") == 1, "123");
static_assert(UTILITY_IS_LITERAL_STRING(L"123") == 1, "L123");
static_assert(UTILITY_IS_LITERAL_STRING(u"123") == 1, "u123");
static_assert(UTILITY_IS_LITERAL_STRING(U"123") == 1, "U123");
}
#define literal(a) "" s
#define strcpy(a, b ) _strcpy(a, literal(b))
char buf[32];
char buf2[32];
const char *p = "hello,";
strcpy(buf, "hello"); // legal
strcpy,(buf, p); // illegal
strcpy(buf, buf2); // illegal
#define STR(s) #s
#define is_string_literal(s) (sizeof(STR(#s)) == sizeof(#s) + 4 \
&& #s[0] == '"' && #s[sizeof(#s)-2] == '"')
#ifdef __GCC__
... use __builtin_constant_p(expr)
#else
... use fallback
#endif