C变量类型断言

时间:2019-04-23 04:04:01

标签: c

      dt|  t|                   u| ra| tm|tra|  alg| fa|
+----------+---+--------------------+---+---+---+-----+---+
|2019-04-22|  1|0e4466fb752e0ff6a...|  2|   |   |h5_rl|   |
|2019-04-22|  1|05ce59ff55b70a805...|  4|   |   | null|   |
|2019-04-22|  1|07bc6ebd8f9d0082d...|  2|   |   |h5_rl|   |

它可以正常工作,但是此代码易碎。明天,我可能会将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

P.S。 1-我知道在C ++中很容易,但是我正在寻找一种C方式。

P.S。 2-我宁愿使用两个断言而不是依赖于编译器警告。通过if检查数字大小应该可以,但是有什么方法可以区分类型是否为无符号?

3 个答案:

答案 0 :(得分: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 :(得分: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

答案 2 :(得分: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

在声明旁边?无论如何,这是更合适的代码。 不需要所有的断言魔术和火箭科学:-)