这是我需要做的。我确信对于许多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
不能在这里使用。
执行此操作以避免类型别名问题和其他类型的未定义行为的正确方法是什么?
答案 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
,则可能会更简洁一些-无需定义lo
和hi
。