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

问题描述 投票:5回答:2

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

我有一个大小为1位的无符号结构成员和一个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的结构成员为什么没有发生隐式类型转换。如果我错过任何基本的比特字段,请纠正我?

c bit-fields
2个回答
2
投票

为了说明,以下使用32位int和32位unsigned int

negVal > p

  • negVal是一个值为-3的int
  • p是一个价值123的unsigned int
  • C 2018 6.5.8 3,讨论>和其他关系运算符,告诉我们通常的算术转换是在操作数上执行的。
  • 6.3.1.8 1定义了通常的算术转换。对于整数类型,通常的算术转换的第一步是对每个操作数执行整数提升。
  • 6.3.1.1 2定义整数提升。 intunsigned int和比这些更宽的整数类型没有变化。对于其他整数类型,它表示:“如果int可以表示原始类型的所有值(由宽度限制,对于位字段),该值将转换为int;否则,它会被转换为unsigned int。“
  • 由于negValint,因此整数促销不会改变。
  • 由于punsigned 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是一个值为-3的int
  • s.bit是一个位为0的位字段。
  • 如上所述,对操作数执行通常的算术转换。
  • 如上所述,通常的算术转换的第一步是对每个操作数执行整数提升。
  • 由于negValint,因此整数促销不会改变。
  • 由于s.bit是一个比int更窄的位场,它将通过整数促销转换。这个一位的位字段可以表示0或1.这两个都可以用int表示,因此规则“如果int可以表示原始类型的所有值(由宽度限制,有点) -field),该值转换为int“适用。
  • 将0转换为int会得到0。
  • 通常的算术转换的下一步是将一个操作数转换为另一个操作数的类型。由于两个操作数现在都是int,因此不需要转换。
  • 转换后,表达式negVal > s.bit已成为-3 > 0
  • 此比较为false,因此结果为0。

5
投票

(把我的评论作为答案)

gcc将s.bit提升为int,所以(negVal > s.bit)(-3 > 0)估值为0

请参阅Should bit-fields less than int in size be the subject of integral promotion?,但您的问题并不重复。


(negVal > p)返回1,因为negVal被提升为unsigned产生一个很大的值,请参阅Signed/unsigned comparisons

© www.soinside.com 2019 - 2024. All rights reserved.