英文:
C: Assert that an expression is a string literal
问题
我想要一个静态断言来确保给定的表达式是一个字符串字面量。我尝试了这个:
#define SAME_TYPES(x, y) __builtin_types_compatible_p(typeof(x), typeof(y))
#define IS_ARRAY(x) !SAME_TYPES((x), &(x)[0])
#define IS_COMPILE_TIME_STR(x) IS_ARRAY(x) && #x[0] == '"'
#define ASSERT_COMPILE_TIME_STR(x) static_assert(IS_COMPILE_TIME_STR(x), "只允许静态分配的编译时字符串,但却得到了这个:" #x)
/*
- ASSERT_COMPILE_TIME_STR("hey"); <-- 这是可以的
- ASSERT_COMPILE_TIME_STR(1234); <-- 这应该失败
*/
不幸的是,`ASSERT_COMPILE_TIME_STR` 不起作用,因为 `#x[0] == '"'` 似乎不是编译时常量。
有没有其他方法可以实现这个?它只需要在 gcc 下编译,所以任何类型的扩展都可以:)
非常感谢
英文:
I would like a static assertion to be sure that a given expression is a string literal. I tried this:
#define SAME_TYPES(x, y) __builtin_types_compatible_p(typeof(x), typeof(y))
#define IS_ARRAY(x) !SAME_TYPES((x), &(x)[0])
#define IS_COMPILE_TIME_STR(x) IS_ARRAY(x) && #x[0] == '"'
#define ASSERT_COMPILE_TIME_STR(x) static_assert(IS_COMPILE_TIME_STR(x), "Only static allocated compile time strings are allowed, but got this: " #x)
/*
* ASSERT_COMPILE_TIME_STR("hey"); <-- this is fine
* ASSERT_COMPILE_TIME_STR(1234); <-- this should fail
*/
Unfortunately, ASSERT_COMPILE_TIME_STR
does not work, because #x[0] == '"'
does not seem to be a compile-time-constant.
Is there some other way to achieve this? It just has to compile with gcc, so any kind of extensions are fine:)
Thanks a lot
答案1
得分: 7
C允许连续的字符串常量,编译器会将它们合并为一个单一的常量。您可以尝试将字符串常量放在与问题中的表达式一起。
#define IS_STR_CONT(x) (void)((void)(x),&(""x""))
关于上述代码的一些注意事项:
- 逗号运算符左侧的
(x)
有助于捕获某些非表达式类型,如0+
- 取地址确保结果是左值
- 逗号运算符左侧和完整表达式上的
void
转换防止出现关于没有效果的表达式的警告
上述代码接受以下内容而没有警告或错误:
IS_STR_CONT("hello");
但在以下情况下会生成一个或多个错误:
IS_STR_CONT(123);
IS_STR_CONT(0+);
IS_STR_CONT(+0);
int i=0;
IS_STR_CONT((i++,"xxx"));
IS_STR_CONT(!"abc");
IS_STR_CONT(4 + "abc");
IS_STR_CONT(*"abc");
IS_STR_CONT("ad" == "abc");
这并不是完美的,但应该能捕获大多数情况。
英文:
C allows consecutive string constants which the compiler combines into a single constant. You can exploit this by attempting to put a string constant in line with the expression in question.
#define IS_STR_CONT(x) (void)((void)(x),&(""x""))
A few notes about the above:
- The
(x)
on the left side of the comma operator helps to catch certain types of non-expressions such as0+
- Taking the address ensures that the result is an lvalue
- The
void
cast on both the left side of the comma operator and the full expression prevent warnings about an expression with no effect.
The above accepts this with no warning or error:
IS_STR_CONT("hello");
While generating one or more errors with these:
IS_STR_CONT(123);
IS_STR_CONT(0+);
IS_STR_CONT(+0);
int i=0;
IS_STR_CONT((i++,"xxx"));
IS_STR_CONT(!"abc");
IS_STR_CONT(4 + "abc");
IS_STR_CONT(*"abc");
IS_STR_CONT("ad" == "abc");
This isn't perfect, but should catch most cases.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论