char是1个字节,整数是4个字节.我想逐字节地从char [4]复制到整数.我想到了不同的方法,但我得到了不同的答案.
char str[4]="abc";
unsigned int a = *(unsigned int*)str;
unsigned int b = str[0]<<24 | str[1]<<16 | str[2]<<8 | str[3];
unsigned int c;
memcpy(&c, str, 4);
printf("%u %u %u\n", a, b, c);
Run Code Online (Sandbox Code Playgroud)
输出为6513249 1633837824 6513249
哪一个是正确的?出了什么问题?
Jon*_*Jon 15
这是一个字节序问题.当您将字符串的第一个字节解释char*为int*整数的最低有效字节时(因为您在x86上运行此代码是小端),而使用手动转换时,第一个字节变为最重要的字节.
把它放到图片中,这是源数组:
a b c \0
+------+------+------+------+
| 0x61 | 0x62 | 0x63 | 0x00 | <---- bytes in memory
+------+------+------+------+
Run Code Online (Sandbox Code Playgroud)
当这些字节被解释为小端架构中的整数时,结果0x00636261为十进制6513249.另一方面,手动放置每个字节产生0x61626300- 十进制1633837824.
当然,将a char*视为int*未定义的行为,因此差异在实践中并不重要,因为您实际上并不允许使用第一次转换.然而,有一种方法可以实现相同的结果,称为类型惩罚:
union {
char str[4];
unsigned int ui;
} u;
strcpy(u.str, "abc");
printf("%u\n", u.ui);
Run Code Online (Sandbox Code Playgroud)
前两个都不正确.
第一个违反了别名规则,可能会失败,因为地址str没有正确对齐unsigned int.要将字符串的字节重新解释为unsigned int具有主机系统字节顺序的字节,您可以使用memcpy以下命令复制它:
unsigned int a; memcpy(&a, &str, sizeof a);
Run Code Online (Sandbox Code Playgroud)
(假设a的大小unsigned int和大小str相同.)
第二个可能会因整数溢出而失败,因为str[0]它被提升为a int,因此str[0]<<24具有类型int,但是shift所需的值可能大于a中可表示的值int.要解决这个问题,请使用:
unsigned int b = (unsigned int) str[0] << 24 | …;
Run Code Online (Sandbox Code Playgroud)
str无论unsigned int主机系统中的字节顺序如何,第二种方法都以big-endian顺序解释字节.