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

时间:2019-02-18 07:31:11

标签: c bit-fields

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

我有一个无符号的结构成员,其大小为一位,一个无符号的int。当我将负值与无符号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的结构成员,为什么不进行隐式类型转换。如果我错过了位域的基础知识,可以纠正我吗?

2 个答案:

答案 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

答案 1 :(得分: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的1位位字段。
  • 如上所述,通常对操作数执行算术转换。
  • 如上所述,常规算术转换的第一步是对每个操作数执行整数提升。
  • 由于negValint,因此整数促销没有改变。
  • 由于s.bit的位域比int窄,因此它将由整数提升转换。这个一位的位字段可以表示0或1。这两个字段都可以用int表示,因此规则“ If int可以表示原始类型的所有值(如受宽度限制,对于位字段),该值将转换为int”适用。
  • 将0转换为int会得出0。
  • 通常的算术转换的下一步是将一个操作数转换为另一个操作数的类型。由于两个操作数现在都是int,因此不需要转换。
  • 转换后,表达式negVal > s.bit变成了-3 > 0
  • 此比较为假,因此结果为0。