首页 > 解决方案 > 使用 memcpy 从数组转换为 int

问题描述

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

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

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

标签: cpointersmemorybytememcpy

解决方案


您的代码充其量具有实现定义的行为,并且在某些情况下具有未定义的行为。

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

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

  • 一些系统使用大端表示,其中第一个字节是整数的最重要部分。字节01 02 03 04代表0x01020304大端系统的价值,例如旧的 Mac、一些手机和嵌入式系统。

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

  • C 标准不排除其他表示形式,其中字节将按其他顺序排列。一些古老的 DEC 系统就是这种情况:PDP-11,最初开发了 C 语言(中间端混合端)。

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

在其他上下文中也可以找到相同的变化,例如日期组件的排序:

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

  • 欧洲使用 little-endian 表示:2021 年 2 月 17 日写成17/02/2021

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

  • 21 在英语中发音为21(大端),而德国人说einundzwanzig(1 和 20,小端,实际上是 3 位数字的中端)。但是 17 是17(小端),在法语中是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;
}

推荐阅读