Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation-defined behavior when byteswap of the signed integers #2070

Open
safocl opened this issue Feb 4, 2025 · 0 comments
Open

Implementation-defined behavior when byteswap of the signed integers #2070

safocl opened this issue Feb 4, 2025 · 0 comments

Comments

@safocl
Copy link
Contributor

safocl commented Feb 4, 2025

Byteswap of the signed integers is the implementation-defined behavior.

x = static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t *>(&sensorData[0])));

can array values ​​be negative?

Standard C++17:
(only non-negative values ​​match the corresponding values ​​of the unsigned integer type)
[basic.fundamental#3]

The range of non-negative values of a signed integer type is a subrange of the corresponding unsigned integer type, the representation of the same value in each of the two types is the same, and the value representation of each corresponding signed/unsigned type shall be the same.

if array values ​​cannot be negative -- __builtin_bswap16(sensorData[0]) is possible

also the static_cast<int16_t>(__builtin_bswap16(*reinterpret_cast<uint16_t *>(&sensorData[0]))) expression is implementation-defined:
[conv.integral#3]

If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.

[basic.types#4]

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T. For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values.

C++17 and C++20 (C++23) standards are different for Shift operators:
C++17:
[expr.shift]

if E1 has a signed type and non-negative value, and E1×2^(E2) is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.
[...]
If E1 has a signed type and a negative value, the resulting value is implementation-defined.

C++20 (C++23):
[expr.shift]

The value of E1 << E2 is the unique value congruent to E1×2^E2 modulo 2N, where N is the width of the type of the result.
[...]
The value of E1 >> E2 is E1/2^E2, rounded towards negative infinity.
[Note [2]: E1 is right-shifted E2 bit positions. Right-shift on signed integral types is an arithmetic right shift, which performs sign-extension. — end note]

and also C++20:
[basic.fundamental#3.sentence-2]

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

Maybe it's worth changing the C++ project standard to at least C++20?

std::byteswap introduced in C++23
and std::bit_cast intoduced in C++20
and std::endian intoduced in C++20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant