uint32_t fail_count = 0;
...
if(is_failed)
if(fail_count < UINT32_MAX - 1 )
++fail_count;
它工作正常,但这段代码很脆弱。明天,我可能会将fail_count
的类型从uint32_t
更改为int32_t
,我忘了更新UINT32_MAX
。
有没有办法断言fail_count
是uint32_t
在我编写我的if
s的功能?
附: 1-我知道在C ++中它很容易,但我正在寻找一种C语言。
附: 2-我更喜欢使用两个断言而不是依赖于编译器警告。通过sizeof
检查数字大小应该有效,但有没有办法区分类型是否未签名?
从C11开始,您可以使用generic selection宏根据表达式的类型生成结果。您可以在static assertion中使用结果:
#define IS_UINT32(N) _Generic((N), \
uint32_t: 1, \
default: 0 \
)
int main(void) {
uint32_t fail_count = 0;
_Static_assert(IS_UINT32(fail_count), "wrong type for fail_count");
}
您当然可以在常规assert()
中使用结果,但_Static_assert
将在编译时失败。
更好的方法是根据类型调度比较,再次使用泛型选择:
#include <limits.h>
#include <stdint.h>
#define UNDER_LIMIT(N) ((N) < _Generic((N), \
int32_t: INT32_MAX, \
uint32_t: UINT32_MAX \
) -1)
int main(void) {
int32_t fail_count = 0;
if (UNDER_LIMIT(fail_count)) {
++fail_count;
}
}
正如您提到的GCC,您可以使用编译器扩展来完成此操作,以防您不使用C11:
首先编写一个模拟C ++ is_same
的宏。然后使用您要比较的类型调用它。
您特定案例的最小示例:
#include<assert.h>
#define is_same(a, b) \
static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")
int main()
{
int fail_count = 0;
is_same(fail_count, unsigned int);
}
编译器断言:
<source>: In function 'main':
<source>:4:3: error: static assertion failed: "fail_count is not unsigned int"
static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")
^~~~~~~~~~~~~
<source>:9:5: note: in expansion of macro 'is_same'
is_same(fail_count, unsigned int);
^~~~~~~
见Demo
那么即使是K&R C以及过去和现在的任何编译器都可以使用的低技术解决方案呢?
将正确的评论放在正确的位置:
/*
* If this type is changed, don't forget to change the macro in
* if (fail_count < UINT32_MAX - 1) below (or file foobar.c)
*/
uint32_t fail_count = 0;
通过适当的封装,这应该指代代码中的一个位置。不要告诉我你在许多地方增加了失败计数。如果你这样做,那么
#define FAIL_COUNT_MAX UINT32_MAX
在宣言旁边?无论如何,那是更恰当和干净的代码。不需要所有断言魔法和火箭科学:-)