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

Swa*_*ala 5 c bit-fields

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

我有一个大小为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;
}
Run Code Online (Sandbox Code Playgroud)

我怀疑的是,如果我将负值与unsigned int进行比较,那么将发生平衡(隐式类型转换).但是如果我比较unsigned int的结构成员为什么没有发生隐式类型转换.如果我错过任何基本的比特字段,请纠正我?

bru*_*uno 5

(把我的评论作为答案)

GCC促进s.bitINT,所以(negVal > s.bit)(-3 > 0)重视0

请参阅大小小于int的位字段是否应该是整体提升的主题?但你的问题并不重复.


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


Eri*_*hil 2

为了便于说明,下面使用 32 位int和 32 位unsigned int.

\n\n

negVal > p

\n\n
    \n
  • negVal是一个int值为 \xe2\x88\x923 的值。
  • \n
  • p值为unsigned int123。
  • \n
  • C 2018 6.5.8 3,讨论了>其他关系运算符,告诉我们通常的算术转换是在操作数上执行的。
  • \n
  • 6.3.1.8 1 定义了常用的算术转换。对于整数类型,通常算术转换的第一步是对每个操作数执行整数提升。
  • \n
  • 6.3.1.1 2 定义整数提升。intunsigned int、 和比这些更宽的整数类型保持不变。对于其他整数类型,它表示: \xe2\x80\x9d 如果 anint可以表示原始类型的所有值(对于位字段,受宽度限制),则该值将转换为int; 否则,它会转换为unsigned int.\xe2\x80\x9d
  • \n
  • 由于negVal是 an int,因此整数提升不会改变它。
  • \n
  • 由于p是 an unsigned int,因此整数提升不会改变它。
  • \n
  • 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。对于intunsigned int, 被int转换为unsigned int
  • \n
  • int将\xe2\x88\x923转换为unsigned int结果 4,294,967,293。(转换定义为UINT_MAX + 1根据需要对值进行多次加或减,即 4,294,967,296,使其处于范围内。这相当于 \xe2\x80\x9cwrapping\xe2\x80\x9d 模 4,294,967,296 或重新解释\xe2\x80\x99s 将 \xe2\x88\x923 的两个补码表示为unsigned int。)
  • \n
  • 转换后,表达式negVal > p变为4294967293u > 123u
  • \n
  • 这个比较是正确的,所以结果是1。
  • \n
\n\n

negVal > s.bit

\n\n
    \n
  • negVal是一个int值为 \xe2\x88\x923 的值。
  • \n
  • s.bit是一个值为 0 的一位位域。
  • \n
  • 如上所述,对操作数执行通常的算术转换。
  • \n
  • 如上所述,通常算术转换的第一步是对每个操作数执行整数提升。
  • \n
  • 由于negVal是 an int,因此整数提升不会改变它。
  • \n
  • 由于s.bit是 比 an 窄的位域int,因此它将通过整数提升进行转换。这个一位位域可以表示 0 或 1。这两者都可以用 来表示int,因此规则 \xe2\x80\x9cIf anint可以表示原始类型的所有值(受宽度限制,对于位字段),该值被转换为int\xe2\x80\x9d 应用。
  • \n
  • 将 0 转换为int0。
  • \n
  • 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。由于现在两个操作数都是int,因此不需要转换。
  • \n
  • 转换后,表达式negVal > s.bit变为-3 > 0
  • \n
  • 这个比较是假的,所以结果是0。
  • \n
\n