c - 为什么这个 bit-hack 代码是可移植的?

标签 c

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/

相关文章:

Cortex M0 不支持 CPSID i 汇编指令

c - 错误: Segmentation fault using fopen and open

c - 当 "pointer to an object type"与 "pointer to a void"比较相等时,如何理解转换规则?

c - 无效的读写valgrind

c - 有没有更简单的方法来完成这项工作?

arrays - C 结构体可以包含指向其他结构体数组的指针(具有不同的长度)

c - 在结构错误中初始化二维数组

c - Arduino millis不工作

c - 在什么情况下我们会出现此错误消息?

c - 如何以编程方式实现特定 USB 设备的序列号和其他详细信息?