C: 断言表达式是字符串文字

huangapple go评论70阅读模式
英文:

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] == &#39;&quot;&#39;` 似乎不是编译时常量。

有没有其他方法可以实现这个?它只需要在 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), &amp;(x)[0])
#define IS_COMPILE_TIME_STR(x)              IS_ARRAY(x) &amp;&amp; #x[0] == &#39;&quot;&#39;
#define ASSERT_COMPILE_TIME_STR(x)          static_assert(IS_COMPILE_TIME_STR(x), &quot;Only static allocated compile time strings are allowed, but got this: &quot; #x)

/*
 * ASSERT_COMPILE_TIME_STR(&quot;hey&quot;); &lt;-- this is fine
 * ASSERT_COMPILE_TIME_STR(1234);  &lt;-- this should fail
 */

Unfortunately, ASSERT_COMPILE_TIME_STR does not work, because #x[0] == &#39;&quot;&#39; 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),&amp;(&quot;&quot;x&quot;&quot;))

关于上述代码的一些注意事项:

  • 逗号运算符左侧的(x)有助于捕获某些非表达式类型,如0+
  • 取地址确保结果是左值
  • 逗号运算符左侧和完整表达式上的void转换防止出现关于没有效果的表达式的警告

上述代码接受以下内容而没有警告或错误:

IS_STR_CONT(&quot;hello&quot;);

但在以下情况下会生成一个或多个错误:

IS_STR_CONT(123);
IS_STR_CONT(0+);
IS_STR_CONT(+0);
int i=0;
IS_STR_CONT((i++,&quot;xxx&quot;));
IS_STR_CONT(!&quot;abc&quot;);
IS_STR_CONT(4 + &quot;abc&quot;);
IS_STR_CONT(*&quot;abc&quot;);
IS_STR_CONT(&quot;ad&quot; == &quot;abc&quot;);

这并不是完美的,但应该能捕获大多数情况。

英文:

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),&amp;(&quot;&quot;x&quot;&quot;))

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 as 0+
  • 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(&quot;hello&quot;);

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++,&quot;xxx&quot;));
IS_STR_CONT(!&quot;abc&quot;);
IS_STR_CONT(4 + &quot;abc&quot;);
IS_STR_CONT(*&quot;abc&quot;);
IS_STR_CONT(&quot;ad&quot; == &quot;abc&quot;);

This isn't perfect, but should catch most cases.

huangapple
  • 本文由 发表于 2023年6月27日 20:38:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76564953.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定