【问题标题】:memcpy of uint8_t to uint16_tuint8_t 到 uint16_t 的 memcpy
【发布时间】:2015-11-18 21:23:19
【问题描述】:

我有代码

#include <iostream>
#include <string.h>
using namespace std;

int main() {
    // your code goes here
    uint8_t x[4] = {55, 11, 0, 20};
    uint16_t y;
    memcpy(&y, &x[0], 2);
    std::cout<<y<<std::endl;
    return 0;
}

(十六进制 55 - 37,十六进制 11 - B) 我希望 y 包含“37B”(即十进制的 - 891)。但是,Y 实际上包含“B37”(即十进制的 2871)。如何在没有字节序交换操作的情况下使用 memcpy 维护顺序。

【问题讨论】:

  • 不管字节顺序如何,37B 是不可能的——那么你已经完全丢失了半个字节。
  • @PaoloM 从示例中可以看出,数组的 2 个元素被复制到一个变量中(即数组元素的 2 倍大小)。您的建议只分配一个数组元素。
  • 除此之外:将所有内容都以十六进制编写并避免以十进制讨论事物会更具可读性。您也可以在代码中执行此操作:例如{0x37, 0x0b, 0x00, 0x14}std::cout &lt;&lt; std::hex &lt;&lt; y &lt;&lt; std::endl;.

标签: c++


【解决方案1】:

memcpy 复制内存。它确实维护了内存字节的顺序。你不能让memcpy 做其他事情。

你的问题是你不想复制内存;您想做一些特定的算术运算(例如,连接两个 8 位值以获得 16 位值)。

整数类型在内存中的确切布局方式是未指定的行为。在您的 CPU 上,您的 memcpy hack 不会执行您想要的算术运算。因此,要做你想做的事,必须做除memcpy之外(或除此之外)的事情。

我建议使用算术运算进行算术运算:您将获得可以确定适用于所有事物的代码*,并且您的程序很可能会执行与 hack 相似(甚至更好)的代码无论如何,尤其是在打开编译器优化的情况下。

*:当然是所有具有相关类型的东西

【讨论】:

  • 使用 shift/OR 从字节数组中生成更宽的值有时称为Endian Agnostic code。是的,当不需要字节序转换时,它通常会优化掉。
【解决方案2】:

您收到 B37 的原因是因为您使用的是 little-endian 机器。

memcpy 的调用符合您的预期。值0x37 复制到y 的第一个字节,而0x0B 复制到y 的第二个字节。而且因为您使用的是小端架构,y 的第一个字节是最不重要的。所以它包含值0xB37

如果您希望x[0] 成为高字节,x[1] 成为y 的低字节,则需要以不依赖字节序的方式进行:

y = x[1];          // y = 0x0B
y |= x[0] << 8;    // y = 0x0B | 0x3700 = 0x370B

这将使y 的值为0x370B。但是,这仍然不是您期望的 0x37B 值。

如果这是您想要的,您需要认识到0x37B 的高字节值为0x03,低字节为0x7B

因此,您需要按如下方式定义x

// note the use of hex constants to make the values more clear
uint8_t x[4] = {0x7b, 0x3, 0x0, 0x14};   

或者你需要执行一些额外的位移来获得你需要的值:

y = x[1];          // y = 0x0B
y |= x[0] << 4;    // y = 0x0B | 0x370 = 0x37B

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    • 2014-07-23
    • 2014-11-05
    • 2018-05-15
    • 2021-11-30
    • 2023-02-09
    相关资源
    最近更新 更多