【发布时间】:2011-11-20 03:49:34
【问题描述】:
我在论坛中遇到了这个问题。答案是这样的:
#define ISUNSIGNED(a) (a >= 0 && ~a >= 0)
//Alternatively, assuming the argument is to be a type, one answer would use type casts:
#define ISUNSIGNED(type) ((type)0 - 1 > 0)
我对此有几个问题。为什么我们需要检查~a >= 0?第二种解决方案是什么?我不明白这句话:“argument is to be a type”。更重要的是,作者指出第一个 #define 在 ANSI C 中不起作用(但在 K&R C 中起作用)。为什么不呢?
【问题讨论】:
-
关于第一部分:带符号的值也可以是正数。因此仅测试
a >= 0是不够的。 -
C 类型是根据值而不是表示定义的。唯一的例外是无符号整数值,您可以假设特定的二进制表示是您一直认为的那样。因此,您应该只对无符号整数类型使用按位运算。其他一切都会给你不可预测的(实现定义的或未定义的)结果。
-
刚刚编辑了我的答案,包括对在 ANSI C 中不起作用的新促销规则的解释。
-
@Kerrek:不是这样。签名类型只有 3 种法律表示。只要您检查基于位运算的解决方案对于 3 种可能的表示形式是否正确,它就是 100% 可移植的。不过要注意的一件事是,在没有负零的非二进制补码系统上,~0 可能是未定义的行为。
-
@maxpayne:应该注意的是,这两个宏都不是测试表达式/类型是否签名的糟糕方法。有更好的方法可以做到这一点,例如
(1?-1:(a))<0。另请注意,由于整数提升问题,所有这些方法对于小于 int 的类型都将失败。