enr*_*856 2 c serialization deserialization
我试图找出将字节数组转换为uint64_t( unsigned long long) 时的错误。
我知道你可以通过轮班来做到这一点,但这不是我的问题。我想用乘法来做到这一点。我想知道为什么在某些情况下乘法没有按计划进行。
这段代码的结果是正确的:
#include <stdio.h>
int main()
{
unsigned char byte[8];
unsigned long long x;
byte[0] = 0x15;
byte[1] = 0x15;
byte[2] = 0x17;
byte[3] = 0x18;
byte[4] = 0x19;
byte[5] = 0x20;
byte[6] = 0x21;
byte[7] = 0x12;
x = (byte[0] * 0x100000000000000) +
(byte[1] * 0x1000000000000) +
(byte[2] * 0x10000000000) +
(byte[3] * 0x100000000);
x = x +
(byte[4] << 24) +
(byte[5] << 16) +
(byte[6] << 8) +
byte[7];
printf("%llx\n", x);
}
Run Code Online (Sandbox Code Playgroud)
结果是1515171819202112,这是正确的。
但在这种情况下,我使用这些字节来代替:
byte[0] = 0x15;
byte[1] = 0x92; // changed
byte[2] = 0x53; // changed
byte[3] = 0x22; // changed
byte[4] = 0xec; // changed
byte[5] = 0x33; // changed
byte[6] = 0x99; // changed
byte[7] = 0x12;
Run Code Online (Sandbox Code Playgroud)
……结果是错误的。
我得到:
159253 21 ec339912。
但是,它应该是:
159253 22 ec339912。
为什么?有什么错误?
在这个子表达式中:
\nbyte[4]<<24\nRun Code Online (Sandbox Code Playgroud)\n你从一个值开始unsigned char。该值首先被提升为type int。有关算术转换的C 标准第 6.3.1.1p2 节详细介绍了此行为:
\n\n\n
int只要可以使用or的地方,就可以在表达式中使用以下内容unsigned int:\n
\n- 具有整数类型(除 int 或 unsigned int 之外)的对象或表达式,其整数转换等级小于或等于\nint 和 unsigned int 的等级。
\n- \n
_Bool类型为、int、signed int或 的位字段unsigned int。如果 an
\nint可以表示原始类型的所有值(对于位字段而言,\n受宽度限制),则该值将转换为\nanint;否则,它会被转换为unsigned int. 这些称为整数提升。所有其他类型都不会因整数提升而改变。
因此,提升后的值byte[4]具有int带符号类型且(很可能)32 位。然后将此int值左移 24。假设原始值为0xec,这会导致值 1 被移入结果的符号位int。
将 1 移入符号位会导致未定义的行为。C 标准第 6.5.7p4 节中有关按位移位运算符的说明对此进行了详细说明:
\n\n\n结果
\nE1 << E2是E1左移E2位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1 \xc3\x97 2 E2,比结果类型中可表示的最大值多减模 1。如果 E1 具有带符号类型和非负值,并且 E1 \xc3\x97 2 E2可在结果类型中表示,则这就是结果值;否则,行为是未定义的。
您可以通过首先将值转换为unsigned long long以使移位有效来纠正此问题。
x=x+((unsigned long long)byte[4]<<24)+(byte[5]<<16)+(byte[6]<<8)+byte[7];\nRun Code Online (Sandbox Code Playgroud)\n