gpt4 book ai didi

将编译时断言作为表达式的一部分但不包含 _Static_assert

转载 作者:行者123 更新时间:2023-11-30 14:45:37 26 4
gpt4 key购买 nike

最终,我想要一个编译时常量宏,它本身包含一个断言。

使用真正的_Static_assert,我可以做类似的事情

#define CEXPR_MACRO_WITH_ASSERTION(Assertion) sizeof(struct{char c; _Static_assert(Assertion,""); })?0:42

(对于像“编译时断言”这样的东西,宏值计算不会在任何目标上溢出,我想将断言保留在宏中,以便它与值紧密耦合)但是像 tcc 这样的编译器没有静态断言,所以我需要模拟它。

#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT[(Cexpr)?1:-1]

是一种常见的方法,但使用 extern 我不能在结构中使用它,所以我可以将它分成两部分

#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])] /*ignore Msg for simplicity's sake*/

并在CEXPR_MACRO_WITH_ASSERTION中使用下划线版本,但在函数上下文中,这会给支持其中包含 VLA 的结构的编译器带来误报:

#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])]
#define CEXPR_MACRO_WITH_ASSERTION(Assert) (sizeof(struct{char c; STATIC_ASSERT_(Assert,""); })?0:42)

int main(void)
{
int x = 0;
CEXPR_MACRO_WITH_ASSERTION(x);
} //compiles on tcc and gcc (clang rejects it because of the vla in a struct)

所以我实际上需要:

#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr)&&ENFORCE_ICEXPR(Cexpr))?1:-1])]

现在我意识到,特别是在 tcc 上,ENFORCE_ICEXPR(强制整数常量表达式)可以简单地用 __builtin_constant_p 替换,但我很好奇是否可以在没有平台的情况下做到这一点依赖性。

所以我想我可以通过尝试将 Cexpr 分配给 enum 常量来测试它,我想出了:

#define ENFORCE_Z(X) _Generic(0LL+(X),ullong:(X),llong:(X)) /*could be just `+(X)` cuz I don't care about floats*/
#define ENFORCE_ICEXPR(X) sizeof( void (*)(enum { ENFORCE_ICEXPR = (int)ENFORCE_Z(X) } ) )

但这让 gcc 和 clang 提示(在 gcc 的情况下是无声的)枚举在声明之外不可见(顺便说一句,这就是这里的意图),所以我诉诸于

#define ENFORCE_ICEXPR(X) sizeof(enum { BX_cat(ENFORCE_ICEXPR__,__COUNTER__) = (int)ENFORCE_Z(X) })

依赖于非标准魔术宏,__COUNTER__

我的问题是,有没有更好的方法来编写ENFORCE_ICEXPR(X)

最佳答案

Perl uses a bit-field instead of an array定义 static_assert 后备:

#define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)

没有编译器实现可变长度位域。

关于将编译时断言作为表达式的一部分但不包含 _Static_assert,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52909065/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com