【问题标题】:How to read sequence of bytes from pointer in C++ as long?如何从 C++ 中的指针读取字节序列?
【发布时间】:2025-12-23 21:20:27
【问题描述】:

我有一个指向 char 数组的指针,我需要继续使用 64 位掩码对每个字节进行异或。我认为最简单的方法是将每个 8 个字节读取为一个 long longuint64_t 并与之异或,但我不确定如何。也许投射到long long* 并取消引用?一般来说,我仍然对指针非常不确定,因此任何示例代码也将不胜感激。谢谢!

编辑:示例代码(只是为了显示我想要的,我知道它不起作用):

void encrypt(char* in, uint64_t len, uint64_t key) {
        for (int i = 0; i < (len>>3); i++) {
            (uint64_t*)in ^= key;
            in += 8;
        }
    }
}

【问题讨论】:

  • 如果你想走那条路,你需要确保你的 char[] 正确对齐。在性能需要之前,一次处理一个字节会更安全。
  • @TheAbelo2 :在您测量并发现最简单的正确解决方案的性能不足之前,性能不是至关重要。
  • &amp;in ^= key; 你的意思可能是*in ^= key;
  • 它不起作用的原因之一是您正在对in 的地址而不是其内容进行异或运算。 (long *)in ^= key;
  • 我知道将 64 位整数排列为 8 个字节序列的三种“明显正确”的方式,而且我很确定我在普通台式计算机上见过这三种方式-- 你真的不应该依赖以任何特定方式排列的 64 位整数的内容。

标签: c++ arrays pointers char uint64


【解决方案1】:

进行 XOR 屏蔽的直接方法是按字节:

void encrypt(uint8_t* in, size_t len, const uint8_t key[8])
{
    for (size_t i = 0; i < len; i++) {
        in[i] ^= key[i % 8];
    }
}

注意:这里的key 是一个 8 字节数组,而不是 64 位数字。这段代码很简单——不需要任何技巧,易于调试。衡量它的性能,如果性能足够好就用它。

一些(大多数?)编译器通过矢量化来优化这些简单的代码。也就是说,所有细节(转换为uint64_t 等)都由编译器执行。但是,如果您尝试在代码中“聪明”,您可能会无意中阻止编译器进行优化。所以尝试编写简单的代码。

附:您可能还应该使用restrict 关键字,这是目前非标准的,但可能需要获得最佳性能。我没有使用它的经验,所以没有将它添加到我的示例中。


如果你的编译器不好,无法启用矢量化选项,或者只是想玩玩,你可以使用这个版本的强制转换:

void encrypt(uint8_t* in, size_t len, uint64_t key)
{
    uint64_t* in64 = reinterpret_cast<uint64_t*>(in);
    for (size_t i = 0; i < len / 8; i++) {
        in64[i] ^= key;
    }
}

它有一些限制:

  • 要求长度能被 8 整除
  • 要求处理器支持未对齐的指针(不确定 x86 - 可能会工作)
  • 编译器可能拒绝向量化这个,导致性能下降
  • 正如 Hurkyl 所指出的,掩码中 8 个字节的顺序不明确(在 x86 上,little-endian,最低有效字节将掩码输入数组的第一个字节)

【讨论】:

  • 什么是 size_t?我以前从未遇到过。
  • std::uint8_t 不是读取对象表示的有效类型,因为它没有义务成为 char 类型,这是唯一允许的类型,因此使用它是非便携和风险UB。然后你的第二部分是非常糟糕的建议和一个非常有效的 UB 生成器,因为投射 from char * 违反了严格的别名(投射 to @ 的余量没有对称性987654330@)
  • 您最后的建议是违反严格别名,因此还要求编译器支持“无严格别名”方言
  • @anatolyg 可移植的方法是独立考虑每个char,你几乎在你的第一个部分得到了但使用std::uint8_t丢失了,这是不能保证的成为char 类型的typedef(我认为它通常是无关紧要的)。如果“使用 64 位类型”是指通过使用更广泛的类型一次处理多个 char,那么不,我不相信有任何可移植的方式来实现这一点 - 你变得依赖于一个平台对 64 位 int 的表示,更糟糕的是,它成为严格混叠的牺牲品 - 因此我觉得有必要明确这一点。
  • @underscore_d : "但是如果memcpys 没有被优化掉,你认为仅仅处理char-by-char 会有什么性能提升吗?" 如果您使用适当的块大小(即8 的倍数)并且整个事情都被矢量化了,那么绝对可以。就个人而言,除非我的实现使用手动 SIMD 内在函数,否则除了逐个字符之外,我不会打扰其他任何事情,因为如果编译器决定不自动矢量化,那就不值得费心了。