从无符号位转换为带符号的较小类型是否可移植?

Is bitshifting from an unsigned to a signed smaller type portable?

我有一个 unsigned short(在目标平台上是 16 位)
它包含两个8位有符号值,一个在低字节,一个在高字节。

#include <vector>
#include <iostream>
int main() {
    unsigned short a = 0xE00E;
    signed char b = a & 0xFF;
    signed char c = ((a >> 8) & 0xFF);
    std::cout << (int)b << std::endl;
    std::cout << (int)c << std::endl;

}

这是可移植的,还是我依赖​​于平台相关行为?
在所有主要编译器(gcc、msvc、clang)上,结果是 14-32,这是预期的输出。

免责声明:我不是语言律师

Is this portable, or am I relying on platform dependent behaviour here?

由于没有指定版本,我用的是最后一个草稿。

那么我们需要检查什么:

  1. unsigned short可以容纳0xE00E并且signed char可以容纳8位吗?
  2. a & 0xFF((a >> 8) & 0xFF)如何转化为signed char
  3. signed char如何转化为int

1。 unsigned short可以容纳0xE00E吗?

Type             | Minimum width 

signed char        8    
short int          16
int                16
long int           32
long long int      64

来源:https://eel.is/c++draft/basic.fundamental

2。 a & 0xFF((a >> 8) & 0xFF)如何转化为signed char?

In particular, arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied

unsigned char or unsigned short can be converted to int if it can hold its entire value range, and unsigned int otherwise;

来源:https://en.cppreference.com/w/cpp/language/implicit_conversion积分推广

AFAIU,在a & 0xFF中,a可以是intunsigned int

如果 sizeof(unsigned short) == sizeof(int) a 将是一个 unsigned int 和一个 int否则。

If the types are the same, that type is the common type.

If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type.

来源:https://en.cppreference.com/w/c/language/conversion 常用算术转换

现在我们需要从 intunsigned int

转到 signed char

Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2N, where N is the width of the destination type.

来源:https://eel.is/c++draft/conv.integral#3

注意:在 C++20 之前是 implementation-defined(来源 https://en.cppreference.com/w/cpp/language/implicit_conversion

和负号的内存表示:

An unsigned integer type has the same object representation, value representation, and alignment requirements ([basic.align]) as the corresponding signed integer type. For each value x of a signed integer type, the value of the corresponding unsigned integer type congruent to x modulo 2N has the same value of corresponding bits in its value representation. [Example 1: The value −1 of a signed integer type has the same representation as the largest value of the corresponding unsigned type. — end example]

来源:https://eel.is/c++draft/basic.fundamental#3

一切顺利。

signed char b = a & 0xFF;
signed char c = ((a >> 8) & 0xFF);

已定义且符合您的期望。

3。 signed char如何转化为int?

又是https://eel.is/c++draft/conv.integral#3。而且它不会修改值。

结论

Is bitshifting from an unsigned to a signed smaller type portable?

C++20

C++20 之前

无符号到有符号的转换是实现定义的。为了防止这种情况发生,我们需要

static_assert(sizeof(unsigned short) < sizeof(int));

而且代码是完全可移植的。