C变量类型断言

问题描述 投票:15回答:3
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_countuint32_t在我编写我的ifs的功能?

附: 1-我知道在C ++中它很容易,但我正在寻找一种C语言。

附: 2-我更喜欢使用两个断言而不是依赖于编译器警告。通过sizeof检查数字大小应该有效,但有没有办法区分类型是否未签名?

c
3个回答
22
投票

从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;
  }
}

1
投票

正如您提到的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


1
投票

那么即使是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

在宣言旁边?无论如何,那是更恰当和干净的代码。不需要所有断言魔法和火箭科学:-)

© www.soinside.com 2019 - 2024. All rights reserved.