如何在ANSI C中确定变量是否为无符号

JAC*_*K M 11 c

我正在学习Peter Van Der Linden的"专家C编程".在A.6章中,写者描述了如何在K&R C中确定变量是否是无符号的.宏如下:

#define ISUNSIGNED(a) (a>=0 && ~a>=0)
Run Code Online (Sandbox Code Playgroud)

这本书很古老,它于1994年首次出版!我之前没有学过K&R C. 问题是如何在ANSI C中确定变量是否是无符号的.

我试图像这样解决问题.由于"0"在ANSI C中是int,并且当与0比较时,除了float,double和long double之外的任何其他数字将通过Integer Upgrade转换为int或unsigned int.所以我想找到unsigned和signed number之间的边.当我将(边缘类型)0与a进行比较时,a的类型将不会改变.宏也是模型如下:

#define ISUNSIGNED(a) (a>=(the edge type)0 && ~a>=(the edge type)0)
Run Code Online (Sandbox Code Playgroud)

我找不到边缘类型,有没有人可以帮我解决问题?我已将"数字"更改为"变量"以获得更准确的表达.

Chr*_*utz 13

这是如何工作的

签名变量必须将其符号存储一些.通常这是最重要的一个,但它可能是其中任何一个.无符号变量没有符号位; 因此,它可以容纳的最低值是0.这意味着对于无符号变量a,表达式a >= 0始终为true.

所以我们有:

( a >= 0 && ~a >= 0 )
Run Code Online (Sandbox Code Playgroud)

如果a是无符号的,则第一个为真(必须是),第二个为真(因为无论值~a是什么,它仍然是无符号值,所以它仍然是>= 0).如果a已签名,则表示如果设置了符号位,a >= 0则为false(并且表达式返回false,表明此变量具有签名类型).如果没有在设置的签位a,那么当~a反转所有的位a,符号位(哪一个它是)进行设置.这意味着它必须是负数,这意味着~a >= 0返回false.

这确实依赖于标准整数促销,就像您期望的那样.

它怎么行不通

unsigned char x = 1; // or whatever

printf("%s\n", ISUNSIGNED(x) ? "TRUE" : "FALSE"); // prints "FALSE"
Run Code Online (Sandbox Code Playgroud)

正如别人指出的那样,unsigned char被提升到一个int因为任何价值~a的一个unsigned char a可以很容易地适应的范围int.这可以说是标准整数提升中的失败(或者整数文字的输入失败).

可能存在可以克服此限制的另一个实现ISUNSIGNEDISSIGNED某个地方.在P99宏库有宏的一些令人费解的用途,许多依靠C99的复杂的宏,但不幸的是宏检查表达式是否签署与否(#define SIGNED(expr) ((1 ? -1 : expr) < (1 ? 0 : expr)))屈从于相同的整数促销.这可能是你能做到的最好的事情(尽管我认为在你想要它的情况下它总比没有好).

  • `P99_SIGNED(expr)` 归结为 `(typeof(expr)) -1 &lt; ((typeof(expr)) 0`,其中它使用了一个巧妙的技巧来避免实际调用 `typeof`(它执行类似 `1 ? -1 : expr` 要在 `expr` 类型中获得 `-1`,请检查 [`P99_PROMOTE_M1`](http://p99.gforge.inria.fr/p99-html/p99__int_8h_source.html#l00375)宏)。 (2认同)