无符号位字段值与有符号值的比较
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 的结构成员,为什么隐式类型转换没有发生。如果我错过了位域的任何基础知识,请纠正我?
(把我的话搬过来作为回答)
gcc 将 s.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 定义整数促销。
int
、unsigned int
和比这些宽的整数类型不变。对于其他整数类型,它表示:“如果一个 int
可以表示原始类型的所有值(受宽度限制,对于位字段),该值将转换为一个 int
;否则,它将转换为 unsigned int
。”
- 因为
negVal
是一个 int
,整数提升不会改变它。
- 因为
p
是一个 unsigned int
,整数提升不会改变它。
- 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。对于
int
和 unsigned int
,int
将转换为 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。
在编写代码时,我在代码中观察到一件事,它与位域值与负整数的比较有关。
我有一个大小为一位的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 的结构成员,为什么隐式类型转换没有发生。如果我错过了位域的任何基础知识,请纠正我?
(把我的话搬过来作为回答)
gcc 将 s.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 定义整数促销。
int
、unsigned int
和比这些宽的整数类型不变。对于其他整数类型,它表示:“如果一个int
可以表示原始类型的所有值(受宽度限制,对于位字段),该值将转换为一个int
;否则,它将转换为unsigned int
。” - 因为
negVal
是一个int
,整数提升不会改变它。 - 因为
p
是一个unsigned int
,整数提升不会改变它。 - 通常算术转换的下一步是将一个操作数转换为另一个操作数的类型。对于
int
和unsigned int
,int
将转换为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。