C标准怎么说?
uint32_t a = 0x11223344;
uint16_t b = a;
打印时,我得到0x3344,这很有意义;所以这必须是合法且正确的行为吗?
答案 0 :(得分:4)
C标准所说的内容归结为以下事实:通过计算模2 16 的值0x11223344
将uint16_t
转换为0x3344
。
但是,到达目标的过程分几个步骤:
uint16_t b = a;
是带有初始化的声明,C 2018 6.7.9 11中对此进行了讨论:
标量的初始值设定项应为单个表达式,可以选择用大括号括起来。对象的初始值是表达式的初始值(转换后);采用与简单赋值相同的类型约束和转换,将标量的类型作为其声明类型的非限定版本。
因此适用简单分配规则。这些将在6.5.16.1 2中讨论:
在简单赋值( = )中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数。
“赋值表达式的类型”是按照6.5.16 3:左操作数的类型。
赋值表达式的类型是左值转换后左操作数将具有的类型。
(在这种情况下,左值转换没有什么特别的;对象uint16_t b
会简单地变成uint16_t
的值,因此类型为uint16_t
。)
根据7.20.1.1 1:uint16_t
的类型当然是一个无符号的16位整数
typedef名称 uint N _t 指定宽度为 N 并且没有填充位的无符号整数类型。
请注意,它是一个无符号的16位整数,最大值为65535,而最大值为65536(2 16 )。这与最后一步有关,即从右操作数到uint16_t
的转换,这在6.3.1.3 1和2中进行了讨论:
将整数类型的值转换为 _Bool 以外的其他整数类型时,如果该值可以用新类型表示,则该值不变。
否则,如果新类型是无符号的,则通过重复添加或减去新类型所能代表的最大值,直到该值在新类型的范围内,来转换该值。
当我们从0x10000
0x11223344
减去65536(0x1122
)时,结果是0x3344
,可以用uint16_t
表示,因此是转换的结果。