我在一个论坛上遇到过这个问题.答案是这样的:
#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)
Run Code Online (Sandbox Code Playgroud)
我对此有几个问题.为什么我们需要检查~a >= 0?第二个解决方案是什么?我不明白这句话:"论证是一种类型".更重要的是,作者指出,首先#define不适用于ANSI C(但在K&R C中可以使用).为什么不?
#define ISUNSIGNED(a) (a >= 0 && ~a >= 0)
Run Code Online (Sandbox Code Playgroud)
对于带正号的有符号值,a >= 0将为真(显然)并且~a >= 0将为假,因为我们已经翻转了位以使符号位现在设置,从而产生负值.因此整个表达式都是错误的.
对于带符号的有符号值,a >= 0将为false(显然),并且不会计算表达式的其余部分; 表达式的整体结果为false.
对于无符号值,a >= 0将始终为真(显然,因为无符号值不能为负).如果我们翻转位,那么~a >= 0也是如此,因为即使最高有效位(符号位)设置为1,它仍然被视为正值.
因此,如果原始值及其按位反转都是正数,则表达式返回true,即它是无符号值.
#define ISUNSIGNED(type) ((type)0 - 1 > 0)
Run Code Online (Sandbox Code Playgroud)
这将使用类型而不是值来调用:ISUNSIGNED(int)或者ISUNSIGNED(unsigned int),例如.
对于int,代码扩展为
((int)0 - 1 > 0)
Run Code Online (Sandbox Code Playgroud)
这是假的,因为-1不大于0.
对于unsigned int,代码扩展为
((unsigned int)0 - 1 > 0)
Run Code Online (Sandbox Code Playgroud)
表达式中的signed 1和0literals被提升为unsigned匹配第一个0,因此整个表达式被计算为无符号比较.0 - 1在无符号算术中将循环导致最大可能的无符号值(所有位设置为1),大于0,因此结果为true.
至于为什么它可以与K&R C一起工作,而不是ANSI C,也许这篇文章可以解释一下:
当扩展unsigned char或unsigned short时,如果int足够大以表示较小类型的所有值,则结果类型为int.否则,结果类型为unsigned int.值保留规则为大多数表达式生成最少的意外算术结果.
我想这意味着当比较一个unsigned short时0,例如,无符号值被转换为一个signed int打破宏的行为.
您可以通过根据(a-a)需要评估为有符号或无符号零而不是0始终签名的文字来解决此问题.