int v;
int sign; // the sign of v ;
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
Q1: 既然 v 是由 int
类型定义的,那么为什么还要再把它转换成 int
呢?跟便携有关系吗?
编辑:
Q2:
sign = v >> (sizeof(int) * CHAR_BIT - 1);
这个片段不是可移植的,因为signed int
的右移位是实现定义的,如何填充左边距位由编译器决定。所以
-(int)((unsigned int)((int)v)
做一些便携的把戏。请解释一下为什么会这样。
unsigned int
的右移 不是总是在左边距位中填充0 吗?
最佳答案
它不是严格可移植的,因为理论上 int
是可能的和/或 unsigned int
有填充位。
在假设的实现中 unsigned int
有填充位,右移 sizeof(int)*CHAR_BIT - 1
从那以后会产生未定义的行为
sizeof(int)*CHAR_BIT - 1 >= WIDTH
但是对于所有 unsigned int
的实现没有填充位——据我所知,这意味着所有现有的实现——代码
int v;
int sign; // the sign of v ;
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
必须设置sign
至 -1
如果v < 0
如果 v >= 0
则为 0 . (注意 - 感谢 Sander De Dycker 指出 - 如果 int
有一个负零,那也会产生 sign = 0
,因为 -0 == 0
。如果实现支持负零并且负零的符号应该是 -1
,这种转移和比较 v < 0
都不会产生这样的结果,因此需要直接检查对象表示。)
投向int
投到unsigned int
之前在转变之前完全是多余的,什么也不做。
它是 - 忽略假设的填充位问题 - 可移植,因为标准规定了到无符号整数类型的转换和无符号整数类型的表示。
转换为无符号整数类型是缩减模 2^WIDTH
, 其中WIDTH
是类型中值位数,因此结果位于 0 到 2^WIDTH - 1
的范围内包容性。
因为 unsigned int
中没有填充位int
范围的大小不能大于 unsigned int
, 以及带符号整数的标准要求 (6.2.6.2) 表示为
- 符号和大小
- 一个的补充
- 补码
最小的可能表示 int
值为 -2^(WIDTH-1)
.所以负int
值(value) -k
转换为 2^WIDTH - k >= 2^(WIDTH-1)
因此设置了最高有效位。
非负 int
另一方面,值不能大于 2^(WIDTH-1) - 1
因此它的值将通过转换保留,并且不会设置最高有效位。
所以当转换的结果移动WIDTH - 1
时右边的位(同样,我们假设 unsigned int
中没有填充位,因此 WIDTH == sizeof(int)*CHAR_BIT
),如果 int
将产生 0值是非负的,一个 1
如果它是负的。
关于c - 为什么这个 bit-hack 代码是可移植的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12855825/