将整数类型的数组作为另一个不相关的整数类型的数组访问的安全且符合标准的方式?

时间:2018-07-19 08:30:51

标签: c++ memory type-conversion c++17 type-safety

这是我需要做的。我确信对于许多C ++开发人员来说,这是一项常规且可识别的编码任务:

void processAsUint16(const char* memory, size_t size) {
   auto uint16_ptr = (const uint16_t*)memory;
   for (size_t i = 0, n = size/sizeof(uint16_t); i < n; ++i) {
      std::cout << uint16_ptr[i]; // Some processing of the other unrelated type
   }
}

问题:我正在使用集成了clang静态代码分析的IDE进行开发,因此不鼓励或强烈建议使用我尝试过的所有类型的转换,除非使用memcpy(我不想使用)泄气。例如,CPP Core Guidelines只是禁止了reinterpret_cast。不鼓励使用C型转换。 static_cast不能在这里使用。

执行此操作以避免类型别名问题和其他类型的未定义行为的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

  

执行此操作以避免类型别名问题和其他类型的未定义行为的正确方法是什么?

您使用memcpy

void processAsUint16(const char* memory, size_t size) {
    for (size_t i = 0; i < size; i += sizeof(uint16_t)) {
        uint16_t x;
        memcpy(&x, memory + i, sizeof(x));
        // do something with x
    }
}

uint16_t可以被复制,所以很好。

或者在C ++ 20中,使用std::bit_cast(笨拙地必须首先通过数组):

void processAsUint16(const char* memory, size_t size) {
    for (size_t i = 0; i < size; i += sizeof(uint16_t)) {
        alignas(uint16_t) char buf[sizeof(uint16_t)];
        memcpy(buf, memory + i, sizeof(buf));

        auto x = std::bit_cast<uint16_t>(buf);
        // do something with x
    }
}

实际上,即使您只是reinterpret_cast,编译器也只会“做正确的事”,即使这是未定义的行为。也许像std::bless之类的方法会为我们提供一种更直接的,非复制的方法,但是在此之前……

答案 1 :(得分:1)

我的偏好是将char数组视为已定义顺序的八位字节序列。如果实际上可以根据目标体系结构将其排序,那么显然这是行不通的,但是实际上,这样的内存缓冲区通常来自文件或网络连接。

void processAsUint16(const char* memory, size_t size) {
    for (size_t i = 0; i < size; i += 2) {
        const unsigned char lo = memory[i];
        const unsigned char hi = memory[i+1];
        const uint16_t x = lo + hi*256;  // or "lo | hi << 8"
        // do something with x
    }
}

请注意,我们在这里不使用sizeof(uint16_t)memory是一个八位字节序列,因此即使CHAR_BITS为16,持有uint16_t仍需要两个字符。

如果可以将memory声明为unsigned char,则可能会更简洁一些-无需定义lohi