无符号位字段值与有符号值的比较

Comparison of Unsigned bit field value with signed values

在编写代码时,我在代码中观察到一件事,它与位域值与负整数的比较有关。

我有一个大小为一位的unsigned结构成员和一个unsigned int。当我将负值与 unsigned int 变量进行比较时,我得到的预期结果为 1,但是当我将结构成员与负值进行比较时,我得到的结果却相反,为 0。

#include <stdio.h>
struct S0
{
   unsigned int bit : 1;
};
struct S0 s;

int main (void) 
{
   int negVal = -3;
   unsigned int p = 123;
   printf ("%d\n", (negVal > p)); /*Result as 1 */
   printf ("%d\n", (negVal > s.bit));/*Result as 0 but expected 1 */
   return 0;
}

我怀疑如果我将负值与 unsigned int 进行比较,那么会发生平衡(隐式类型转换)。但是,如果我比较 unsigned int 的结构成员,为什么隐式类型转换没有发生。如果我错过了位域的任何基础知识,请纠正我?

(把我的话搬过来作为回答)

gccs.bit 提升为 int,因此 (negVal > s.bit) (-3 > 0) 的值为 0

请参阅 ,但您的问题不是它的副本。


(negVal > p) returns 1 因为 negVal 被提升为 unsigned 产生了很大的价值,见 Signed/unsigned comparisons

为了说明,下面使用了一个32位的int和一个32位的unsigned int

negVal > p中:

  • negVal 是一个 int,值为 −3。
  • p 是一个 unsigned int,值为 123。
  • C 2018 6.5.8 3,讨论了>和其他关系运算符,告诉我们通常的算术转换是对操作数执行的。
  • 6.3.1.8 1 定义了通常的算术转换。对于整数类型,通常算术转换的第一步是对每个操作数执行 整数提升
  • 6.3.1.1 2 定义整数促销。 intunsigned int 和比这些宽的整数类型不变。对于其他整数类型,它表示:“如果一个 int 可以表示原始类型的所有值(受宽度限制,对于位字段),该值将转换为一个 int;否则,它将转换为 unsigned int。”
  • 因为 negVal 是一个 int,整数提升不会改变它。
  • 因为 p 是一个 unsigned int,整数提升不会改变它。
  • 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。对于 intunsigned intint 将转换为 unsigned int
  • int −3 转换为 unsigned int 结果为 4,294,967,293。 (转换定义为将 UINT_MAX + 1(即 4,294,967,296)加或减到该值所需的次数以使其在范围内。这相当于“包装”模 4,294,967,296 或重新解释二进制补码表示−3 作为 unsigned int.)
  • 转换后,表达式negVal > p变成了4294967293u > 123u
  • 这个比较是正确的,所以结果是 1。

negVal > s.bit中:

  • negVal 是一个 int,值为 −3。
  • s.bit 是一个值为 0 的一位位域。
  • 如上,对操作数进行通常的算术转换。
  • 如上所述,通常算术转换的第一步是对每个操作数执行整数提升。
  • 因为 negVal 是一个 int,整数提升不会改变它。
  • 因为 s.bit 是一个比 int 窄的位域,它将被整数提升转换。这个一位位域可以表示 0 或 1。这两者都可以用 int 表示,因此规则“如果 int 可以表示原始类型的所有值(如受宽度限制,对于位域),该值被转换为 int”适用。
  • 将 0 转换为 int 结果为 0。
  • 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。由于两个操作数现在都是 int,因此不需要转换。
  • 转换后,表达式negVal > s.bit变成了-3 > 0
  • 这个比较是错误的,所以结果是 0。