在C++中将有符号整数当作无符号整数进行写操作

3

reinterpret_cast对于这个问题是否安全,它是实现这个功能的最佳方式吗?

例如,在下面的代码中,我有一个名为ibytestream的类,它允许从中读取uint16_tint16_tibytestream::next是一个vector<unsigned char>::iterator

inline ibytestream& operator>>(ibytestream& stream, uint16_t& data) {
    data = 0;
    data |= *stream.next++;
    data <<= 8;
    data |= *stream.next++;
    return stream;
}

inline ibytestream& operator>>(ibytestream& stream, int16_t& data) {
    return stream >> reinterpret_cast<uint16_t&>(data);
}

我不想复制转换字节为整数的代码,所以我在有符号版本中使用了 reinterpret_cast 来重用无符号版本的代码。它在我的机器上运行良好,但它会在其他现代机器上一般运行吗?


这难道不会违反严格别名规则吗?https://dev59.com/43VD5IYBdhLWcg3wE3Ro - André
2
@Andre 这个规则允许在整数类型和它的有符号/无符号变体之间进行别名处理。 - M.M
2个回答

3

是的,这是安全的。

确定这一点需要遵循标准的三个部分:

  1. 有符号类型和无符号类型的对齐要求相同
  2. 允许在具有相同对齐要求的类型之间进行指针转换
  3. 当执行glvalues之间的转换时,如果对应指针之间的转换有效,则转换是有效的。

对于每种标准有符号整数类型,都存在一个相应的(但不同的)标准无符号整数类型:unsigned charunsigned short intunsigned intunsigned long intunsigned long long int,每种类型占用相同数量的存储空间并具有相同的对齐要求。

可以将对象指针显式转换为不同类型的对象指针。将类型为“指向T1的指针”的prvalue转换为类型为“指向T2的指针”(其中T1和T2均为对象类型且T2的对齐要求不严格于T1)并返回到其原始类型,可以得到原始指针值。

如果可以使用reinterpret_cast将类型为T1的表达式的指针显式转换为“指向T2的指针”,则可以将类型为T1的glvalue表达式转换为类型“引用T2”。结果指向与源glvalue相同的对象,但是具有指定的类型。


1
我认为你忽略了M.M在评论中提到的部分,即你可以通过相应的无符号类型表达式访问有符号整数对象。 - MSalters

1

是的,这应该完全没问题。(在整数和字节数组之间移动可能存在潜在的大小端问题,但这是另一个问题,适用于有符号和无符号数字。)

完全不同的事情:这一位:

data = 0;
data |= *stream.next++;

"...可以简化:"
data = *stream.next++;

我认为我的代码不会有字节序问题。无论底层机器的字节序如何,字节始终会以大端方式读取。此外,我没有简化代码只是为了让它看起来一致(例如,在多行中重复使用 data |= *stream.next++;),我认为我的编译器足够聪明,可以进行优化。 - Bernard
只有在需要跨架构的可移植性时才会出现问题,而似乎您并不需要它。一切都好。 - Petter Hesselberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接