使用 memcpy 将数组转换为 int

using memcpy to convert from array to int

我正在试验指针操作,并决定尝试使用 memcpy 直接从内存中复制,从而将数字数组转换为整数。

char aux[4] = {1,2,3,4}; 
int aux2 = 0;
memcpy((char*) &aux2, &aux[0], 4);
printf("%X", aux2);

我预计结果是 0x1020304,因为我正在将确切的字节从一个字节复制到另一个字节,但是 printf 给了我结果 0x4030201,这几乎是我想要的输出,只是倒过来了。为什么会发生这种情况,有没有办法以“正确”的顺序获得结果?

您的代码至多具有实现定义的行为,在某些情况下具有未定义的行为。

类型 int 的大小可能不同于 4:在 16 位系统上,int 通常只有 2 字节的大小。您在此类系统上会有未定义的行为。

在常规的 32 位系统上,int 有 4 个字节,但是这 4 个字节在内存中的存储顺序是实现定义的,这个问题称为 endianness:

  • 一些系统使用big-endian表示,其中第一个字节是整数的最高有效部分。字节 01 02 03 04 表示 big-endian 系统上的值 0x01020304,例如较旧的 Mac、某些手机和嵌入式系统。

  • 相反,当今大多数个人计算机使用 小尾数法 表示,其中第一个字节包含整数的最低有效部分。字节 01 02 03 04 表示小端系统(例如您的系统)上的值 0x04030201

  • C 标准不排除其他表示形式,其中字节将采用其他顺序。一些古老的 DEC 系统就是这种情况:PDP-11,最初开发 C 语言(middle-endianmixed-endian ).

虽然令人惊讶,但小端顺序非常合乎逻辑,因为偏移量 n 处的字节包含表示 2n 之间的值的位*82n*8+7。 Endianness 是一个文化问题,这两种选择对于长期用户来说似乎很自然。

在其他上下文中发现了相同的变化,例如日期组件的排序:

  • 日本使用大端表示法:2021 年 2 月 17 日写成 2021.02.17

  • 欧洲使用小端表示法:2021 年 2 月 17 日写成 17/02/2021

  • 美国使用中端表示法:2021 年 2 月 17 日写成 02/17/2021

  • 21 在英语中发音为 twenty-one(big-endian),而德语发音为 einundzwanzig(一和二十,小端,实际上是 3 位数字的中端)。但是 17 是 seventeen(小端),在法语中是 dix-sept(大端)。

  • 西方语言以大端格式书写数字(我 42 岁)但闪米特文字使用小端顺序:希伯来语(אני בת 42) 和阿拉伯语 (أنا ٤٢ سن​​⑩) 都使用小端顺序,因为它们是从右到离开了。

这里有一个更便携的版本来测试内存表示:

#include <stdio.h>
#include <string.h>

int main() {
    unsigned int aux2 = 0x01020304;
    unsigned char aux[sizeof(unsigned int)]; 
    memcpy(&aux, aux2, sizeof(aux));
    printf("%X is represented in memory as", aux2);
    for (size_t i = 0; i < sizeof(aux); i++)
        printf(" %02X", aux[i]);
    printf("\n");
    return 0;
}