将 32 位整数值转换为无符号 16 位整数

Converting 32-bit integer value to unsigned 16-bit integer

C 标准是怎么说的:

uint32_t a = 0x11223344;
uint16_t b = a;

打印时,我得到 0x3344,这是有道理的;所以这一定是合法和正确的行为?

C 标准所说的归结为 0x11223344 通过计算值模 216 转换为 uint16_t,即 0x3344.

但是,它到达那里的过程有几个步骤:

uint16_t b = a;是带有初始化的声明,在C 2018 6.7.9 11:

中讨论

The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.

因此适用简单赋值规则。这些在 6.5.16.1 2:

中讨论

In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.

“赋值表达式的类型”是左操作数的类型,根据 6.5.16 3:

The type of an assignment expression is the type the left operand would have after lvalue conversion.

(在这种情况下,左值转换没有什么特别之处;对象 uint16_t b 只会变成 uint16_t 值,因此类型是 uint16_t。)

uint16_t 的类型当然是一个无符号的 16 位整数,根据 7.20.1.1 1:

The typedef name uintN_t designates an unsigned integer type with width N and no padding bits.

注意,作为无符号的16位整数,其最大值为65535,比其大一为65536(216)。这与最后一步有关,即从右操作数到 uint16_t 的转换,这在 6.3.1.3 1 和 2:

中进行了讨论

When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

当我们从0x112233440x1122次中减去65536(0x10000)时,结果是0x3344,可以用一个uint16_t来表示,这就是转换的结果。