提问人:Pentakorr 提问时间:6/22/2023 最后编辑:Vlad from MoscowPentakorr 更新时间:6/23/2023 访问量:89
如果我们比较 unsigned short int 和 unsigned char(比较位)会发生什么?(C语言)
what happens if we compare unsigned short int and unsigned char (comparing the bits)? (in C language)
问:
例如:
unsigned char mask1 = 0x55; //01010101
unsigned short int mask2 = 0x8055;//1000000001010101
unsigned short int res = 0; //0000000000000000
res = mask1 | mask2;
那么现在的比特是什么?res
它从 2 个字节转换为 4 个字节吗?而“空白”会是零吗?mask1
我的意思是,从逻辑上讲,它会这样工作吗?
res = mask1 | mask2 = 01010101 | 1000000001010101
0000000001010101
| 1000000001010101
----------------
1000000001010101
答:
表达式的两个操作数
mask1|mask2;
转换为类型(或者如果类型无法表示操作数的所有值),因为整数升级保留了操作数中存储的值。int
unsigned int
int
来自 C 标准(6.5.12 按位(包括 OR 运算符)
3 通常的算术转换是在操作数上执行的。
和
(6.3.1.8 常用算术转换)
1 许多期望算术类型操作数的运算符会导致 转化和产生结果类型的方式类似。目的是 确定操作数和结果的常见实数类型。
这种模式称为通常的算术转换: 否则(注意:如果两个操作数都不是实数类型 - 由我添加), 整数提升在两个操作数上执行
和 (6.3.1.1 布尔值、字符和整数)
如果 int 可以表示原始类型的所有值(如限制 按宽度,对于位域),该值将转换为 int; 否则,它将转换为无符号整数。这些被称为 整数促销。所有其他类型都由整数保持不变 促销。
因此,例如,存储在内部类型的对象中的值将在该类型的对象中表示,前提是 等于 。存储在该类型的对象中的值将在内部表示,例如0x55
unsigned char
int
0x00000055
sizeof( int )
4
0x8055
unsigned short
0x00008055
在此作业中
res= mask1|mask2;
结果将转换回类型 。unsigned short
评论
int
int
short
unsigned int
这个答案将假设一个具有 8 位字符类型、16 位和 32 位的主流系统(现实世界中所有主流的 32 位和 64 位苦味都是这种情况)。short
int
首先查看隐式类型升级规则。在这种特殊情况下如何工作:
C 语言中的每个操作数都有自己的小行,说明如何处理隐式升级。如果是 ,我们可以看一下 C17 6.5.12 “按位包含 OR 运算符”:|
约束
每个操作数都应具有整数类型。
语义
通常的算术转换是在操作数上执行的。
正如我们从本文顶部的链接中了解到的那样,整数升级是通常算术转换的一部分。所以在表达式中,两个操作数都是小整数类型,因此被提升为有符号的操作数。这有点不幸,因为我们希望避免使用像瘟疫这样的有符号操作数进行按位算术,尽管在这种特定情况下它没有区别。我们将得到0x00008055和0x00000055 0x55而不是0x8055和 - 基本上只是零填充。res = mask1 | mask2;
int
因此,它是 100% 等价的,并且结果是 的类型。res = (int)mask1 | (int)mask2;
mask1 | mask2
int
接下来,它存储在 .然后发生的是“分配期间的转换”,6.5.16:res
unsigned short
在简单赋值 () 中,右操作数的值被转换为 赋值表达式,并替换存储在由左操作数指定的对象中的值。
=
C17 6.3.1.3 中提供了此转换所需的具体规则:
否则,如果新类型为无符号,则通过重复添加或减去比新类型中可以表示的最大值多一个来转换该值,直到该值在新类型的范围内
这种转换的工作方式类似于模数,或者如果您要对原始值进行二进制截断,则简单地丢弃最高有效字节。
在这种特定情况下,我们有一个 with 值,它被转换为 with value 。int
0x00008055
unsigned short
0x8055
关于“分配期间的转换”的一个奇怪的说明是,所有这些行也都发生了这种情况:
unsigned char mask1 = 0x55; //01010101
unsigned short int mask2 = 0x8055;//1000000001010101
unsigned short int res = 0;
这里的数字等,在形式上称为整数常量。C 中的整数常量具有根据各种复杂规则(C17 6.4.4.1)选择的类型 - 我不会在这里提及它们,但现在我们可以注意到整数常量的类型永远不会小于 。因此,在上述所有初始化过程中,我们都有从左操作数类型到类型的隐式转换。0x55
int
int
会发生什么..比较和...?
unsigned short int
unsigned char
OP大多有它。
通常的促销活动
运算符 like 和 else 首先提升每个比 to 更窄且值不变的对象。如果包含窄类型范围,则对象变为 ,否则变为 .|, ^, &, + , -
int/unsigned
int/unsigned
int
int
unsigned
在 OP 的情况下,可能提升到(或者可能是 16 位)。当然会变成一个.unsigned short int
int
unsigned
unsigned
unsigned char
int
转换为普通类型
然后,排名较低的对象将转换为与排名较高的对象相同的对象。这可能涉及将负数转换为负数或将某些整数转换为浮点数的值更改。int
unsigned
在 OP 的情况下,2 个操作数是 then(或者可能是 if 是 16 位)。使用 OP 的值时,此步骤中不会发生值更改。int
unsigned
unsigned
运算符 |
applied
mask1 | mask2
然后几乎按照 OP 假设的 2 秒执行。int
0b00000000`00000000`00000000`01010101
| 0b00000000`00000000`10000000`01010101
-------------------------------------
0b00000000`00000000`10000000`01010101
或将 16 位作为 2 .int/unsigned
unsigned
0b00000000`01010101
| 0b10000000`01010101
-------------------
0b10000000`01010101
赋值缩小了类型范围
然后将 (或 ) 结果转换为 然后进行赋值。int
unsigned
unsigned short
当该值可在新的窄类型中表示时,即保存的值。否则,如果目标类型是有符号整数,则该值将以实现定义的方式进行转换。最常见的实现定义方式只是使用最低有效位。否则,如果目标类型是无符号整数,则使用最低有效位(即“mod”(最大值 + 1))。
在 OP 的情况下,结果在 和 的范围内产生一个值,因此被保存。mask1 | mask2
unsigned short
0b1000000001010101
评论
mask1
char mask1 = 0x88;
char ...
res