从无符号到有符号的较小类型的位移是否可移植?

发布于 2025-01-14 18:45:31 字数 490 浏览 4 评论 0原文

我有一个无符号短(在目标平台上是 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,这是预期的输出。

I have a unsigned short (which is 16 bit on the target platforms)
It contains two 8-bit signed values, one in the lower byte, one in the higher byte.

#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;

}

Is this portable, or am I relying on platform dependent behaviour here?
On all major compilers (gcc, msvc, clang), the result is 14 and -32, which is the expected output.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

耳根太软 2025-01-21 18:45:32

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

这是可移植的,还是我依赖​​于平台相关的行为?

由于没有指定版本,我使用了最后的草案。

那么我们需要检查什么:

  1. unsigned short 能否容纳 0xE00E 以及 signed char 能否容纳 8 位?
  2. 如何a & 0xFF((a >> 8) & 0xFF) 转换为 signed char
  3. signed char 如何转换为 int

1. unsigned long可以容纳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

特别是,算术运算符不接受小于 int 的类型作为参数,并且会自动应用积分提升

如果 unsigned char 或 unsigned Short 可以保存其整个值范围,则可以将其转换为 int,否则可以转换为 unsigned int;

来源:https://en.cppreference.com/w/cpp/language/implicit_conversion< /a> 积分提升

AFAIU,在a & 0xFFa 可以是 intunsigned int

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

如果类型相同,则该类型为公共类型。

如果无符号类型的转换等级大于或等于有符号类型的等级,则有符号类型的操作数将隐式转换为无符号类型。

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

现在我们需要从 intunsigned int 转换为 signed char

否则,结果是与源整数模 2N 一致的目标类型的唯一值,其中 N 是目标类型的宽度。

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

注意:在 C++20 之前是实现定义的(来源 https://en.cppreference.com/w/cpp/language/implicit_conversion

以及负号的内存表示:

无符号整数类型与相应的有符号整数类型具有相同的对象表示、值表示和对齐要求 ([basic.align])。
对于有符号整数类型的每个值 x,与 x 模 2N 同余的相应无符号整数类型的值在其值表示中具有相同的对应位值。
[示例 1:有符号整数类型的值 -1 与相应无符号类型的最大值具有相同的表示形式。
-结束示例]

来源: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再次。并且它不会修改该值。

结论

从无符号到有符号的较小类型的位移是否可移植?

在 C++20 中

在 C++20 之前

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

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

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

Disclaimer: I am no language lawyer

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

Since there is no version specified, I used last draft.

So what did we need to check:

  1. Can unsigned short hold 0xE00E and signed char can hold 8 bits?
  2. How a & 0xFF and ((a >> 8) & 0xFF) are transformed into signed char?
  3. How signed char is transformed into int?

1. Can unsigned short hold 0xE00E?

Type             | Minimum width 

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

Source : https://eel.is/c++draft/basic.fundamental

2. How a & 0xFF and ((a >> 8) & 0xFF) are transformed into 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;

Source: https://en.cppreference.com/w/cpp/language/implicit_conversion Integral promotion

AFAIU, in a & 0xFF, a can be an int or unsigned int.

If sizeof(unsigned short) == sizeof(int) a will be an unsigned int and an
int otherwise.

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.

Source: https://en.cppreference.com/w/c/language/conversion Usual arithmetic conversions

Now we need to go to signed char from int or unsigned int

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.

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

Note: is implementation-defined until C++20 (source https://en.cppreference.com/w/cpp/language/implicit_conversion)

And the memory representation of an negative signed:

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]

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

All good.

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

Are defined and what you expect.

3. How signed char is transformed into int?

It's https://eel.is/c++draft/conv.integral#3 again. And it wont modified the value.

Conclusion

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

In C++20

Yes

Before C++20

The conversion unsigned to signed is implementation defined. To prevent this to happen we need to

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

And the code is fully portable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文