处理低级字节操作时reinterpret_cast是否错误?

时间:2012-12-30 23:17:55

标签: c++ casting c++11 reinterpret-cast

我正在编写一个websocket服务器,我必须处理需要取消屏蔽的屏蔽数据。

掩码是unsigned char [4],数据也是unsigned char *缓冲区。

我不想逐字节XOR,我更喜欢一次XOR 4字节。

uint32_t * const end = reinterpret_cast<uint32_t *>(data_+length);
for(uint32_t *i = reinterpret_cast<uint32_t *>(data_); i != end; ++i) {
    *i ^= mask_;
}

在这种情况下使用reinterpret_cast有什么问题吗?

替代方案是以下代码,它不是那么明确而且不那么快:

uint64_t j = 0;
uint8_t *end = data_+length;
for(uint8_t *i = data_; i != end; ++i,++j) {
    *i ^= mask_[j % 4];
}

我非常喜欢替代品,包括依赖于c ++ 11功能的替代品。

2 个答案:

答案 0 :(得分:8)

这种方法存在一些潜在的问题:

  1. 在某些系统中,类型大于char的对象需要正确对齐才能访问。 uint32_t的典型要求是对象与可被4整除的地址对齐。
  2. 如果length / sizeof(uint32_t) != 0循环可能永远不会终止。
  3. 根据系统的结尾性mask需要包含不同的值。如果mask由合适数组的*reinterpret_cast<uint32_t>(char_mask)生成,则该数组不应为数组。
  4. 如果这些问题得到解决,reinterpret_cast<...>(...)可用于您所拥有的情况。重新解释指针的含义是此操作存在的原因之一,有时需要它。我会创建一个合适的测试用例来验证它是否正常工作,以避免在将代码移植到不同平台时不得不解决问题。

    我个人会采用不同的方法,直到分析显示它太慢:

    char* it(data);
    if (4 < length) {
        for (char* end(data + length - 4); it < end; it += 4) {
            it[0] ^= mask_[0];
            it[1] ^= mask_[1];
            it[2] ^= mask_[2];
            it[3] ^= mask_[3];
        }
    }
    it != data + length && *it++ ^= mask_[0];
    it != data + length && *it++ ^= mask_[1];
    it != data + length && *it++ ^= mask_[2];
    it != data + length && *it++ ^= mask_[3];
    

    我肯定在软件中使用了许多类似的方法,这些方法非常快,并且没有发现它们是一个值得注意的性能问题。

答案 1 :(得分:2)

在这种情况下reinterpret_cast并没有特别的错误。但是,要小心。

现有的32位循环不正确,因为它不适用于有效负载不是32位大小的倍数的情况。我猜想有两种可能的解决方案:

  • 在for循环检查中用!=替换<(这是人们使用<的原因,而不是因为他们是愚蠢的......)并且进行尾随字节顺序为1-3个字节
  • 安排缓冲区,使有效负载部分的缓冲区大小为32位的倍数,并且只是额外字节的XOR。 (假设代码在将字节返回给调用者时检查有效负载长度,因此这无关紧要。)

此外,根据代码的结构,您可能还需要处理某些CPU的未对齐数据访问。如果在32位对齐的缓冲区中有整个帧缓冲,标头和全部,并且如果有效负载长度小于126字节或大于65,535字节,则屏蔽密钥和有效负载都将未对齐。 / p>

无论价值多少,我的服务器都使用类似第一个循环的东西:

for(int i=0;i<n;++i)
    payload[i]^=key[i&3];

与32位选项不同,这基本上不可能出错。