Skip to content

Insight output does not match input when casting signed MIN_SHORT to unsigned int #706

@PennRobotics

Description

@PennRobotics

It's possible this comes down to default compiler flags. Nevertheless, I am trying to pick apart how C types are being cast in order to demonstrate fast vector operations on a basic microcontroller without needing extra range checking and have found a handful of frustrations, the two most notable:

  • casting 0x8000 from a int16_t (-32768) to a uint32_t results in 2^32 − 32768 (unwanted)
  • casting 0x8000 from a int16_t to a uint16_t and then (unwanted) to uint32_t results in 32768 (wanted)

Here is the bare example:

#include <iostream>
#include <cstdint>

int main() {
    int16_t a = (int16_t)0x8000;
    std::cout << a << std::endl;
    std::cout << (uint32_t)a << std::endl;
    std::cout << (uint32_t)(uint16_t)a << std::endl;
}

with output (in clang, gcc, and MSVC)

-32768
4294934528
32768

…and the corresponding Insights output:

#include <iostream>
#include <cstdint>

int main()
{
  int16_t a = static_cast<short>(32768);
  std::cout.operator<<(a).operator<<(std::endl);
  std::cout.operator<<(static_cast<unsigned int>(a)).operator<<(std::endl);
  std::cout.operator<<(static_cast<unsigned int>(a)).operator<<(std::endl);
  return 0;
}

It is clear the last two cout lines will have the same output, but here it is:

-32768
4294934528
4294934528

For my application, this doesn't end up having any ill side effect other than setting the OV flag on x86 as any other number casts correctly, although I don't know that every architecture would have the same method of casting and would also be free of side effects. Thus, I wanted to know exactly how each cast was occurring and which argument type of cout is called, and if there is a good way to force the cast to be always correct with a single function or cast.

If I insert another static_cast<unsigned short>(...) in the third line, the output matches again, so it's possible two static_cast should be chained but one is being cast (hehe) away

(reinterpret_cast on its own is forbidden by some compilers, and changing the code to allow the non-static casts makes the demo harder to understand.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions