thread.exe

[std-proposals] Type modifier to disable integer promotion

26emails11participants29 Mar 2025 – 1 Apr 2025
FV
Frederick Virchanza Gotham29 Mar 2025, 18:58 UTC
2

It's horrible when you use a "std::uint16_t" only to find that it


promotes to a signed 32-Bit integer. Believe it or not, I recently


wrote the following code:

FV
Frederick Virchanza Gotham29 Mar 2025, 19:02 UTC

Re: [std-proposals] Type modifier to disable integer promotion

3

It's horrible when you use a "std::uint16_t" only to find that it


promotes to a signed 32-Bit integer. Believe it or not, I recently


wrote the following code:


        using std::uint_fast32_t;


        // We can't use uint_fast32_t if it undergoes promotion,


        // so instead use long unsigned (which might be 64-Bit)


        typedef typename std::conditional<


            std::is_same< uint_fast32_t, decltype(uint_fast32_t() +


uint_fast32_t()) >::value,

            uint_fast32_t,


            long unsigned >::type UIntType;


So how about if we could tell the compiler that we want to use a


specific integer type, and that we don't want it to promote. Perhaps


here's how we'd define such an integer:


    short unsigned _NoPromo n = 0xFFFF;


And similarly, if we already have a variable, and we want to do some


calculations without it promoting at some point, then we make a


_NoPromo reference to it:


    short unsigned original_variable = 0xFFFF;


    short unsigned _NoPromo &safe_variable = original_variable;


    safe_variable = ~safe_variable; // no promotion takes place here

JW
Jonathan Wakely29 Mar 2025, 21:04 UTC

Re: [std-proposals] Type modifier to disable integer promotion

1

On Sat, 29 Mar 2025, 19:02 Frederick Virchanza Gotham via Std-Proposals, <


std-proposals_at_[hidden]> wrote:


Why?


On what platform in existence today does a type that's at least 32 bits


promote?


The "fast" integer types are pretty much a waste of time. If unsigned long


is acceptable for your code, why not just use that unconditionally?


Or why not unsigned int? If uint_fast32_t promotes then it must be lower


rank than int, so unsigned int would have greater rank than uint_fast32_t,


and support at least all the values that uint_fast32_t supports, and not


undergo promotion. Why is unsigned long preferable to unsigned int?

TM
Thiago Macieira30 Mar 2025, 03:41 UTC

Re: [std-proposals] Type modifier to disable integer promotion

4
HH
Howard Hinnant30 Mar 2025, 02:36 UTC

Re: [std-proposals] Type modifier to disable integer promotion

1

Fwiw I’ve recently been working this area as a library, as opposed to a change to the language:



https://github.com/HowardHinnant/bbi


It looks like:


    #include "bbi.h"


    #include <iostream>


    #include <type_traits>


    int


    main()

    {


        using namespace bbi::wrap;


        u16 x{0xFFFF};


        u16 y{1};


        auto z = x + y; // no integral promotion!


        std::cout << z << '\n’; // prints out 0


        std::cout << sizeof(z) << '\n’; // prints out 2


        static_assert(std::is_same_v<decltype(z), decltype(x)>);

    }


I’m not proposing bbi to the std. But if its design influences something that somebody else proposes, I’m good with that. Or if the open source code is simply useful to somebody else, I’m good with that too.


Howard

BR
Bjorn Reese30 Mar 2025, 14:19 UTC

Re: [std-proposals] Type modifier to disable integer promotion

JV
Julien Villemure-Fréchette1 Apr 2025, 01:54 UTC

Re: [std-proposals] Type modifier to disable integer promotion

1

The "abstract machine" as defined by the standard only defines built-in integer operations (arithmetic and comparison) for the types int, long and long long. In most cases this means arithmetic is only defined for 2 sizes of integer. There is no arithmetic operation that can be done directly on types smaller than int, like a short or signed char. Since std::uint_16 is typically a typedef to unsigned short on machines where short is 16 bits wide, then arithmetic cannot be performed directly on uint_16.


Most likely, there could exist machines which support arithmetic only for its natural word size (which is int), while also supporting reading/writing smaller size integer to memory. In hardware terms, this could mean the ALU only supports int as operands. I think that recent RISC architectures tend to implement only 2 sizes for integer built-in operations (int and long).


Since arithmetic on small integer is not possible, then those small integers must undergo a conversion to widen the integer so that it can be input to the ALU.


There's one point that is very nasty about promotions IMHO: it is when the promotion changes the signedness of the operand. This is especially bad because it will change the semantics of comparisons. This signedness change behavior is also fragile when compiling to different architectures: a signed char or a short could promote to either signed int or unsigned int depending on the target machine. It would be better if promotions could never change signedness.


Julien V.


On March 29, 2025 3:02:22 p.m. EDT, Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> wrote:

HH
Howard Hinnant1 Apr 2025, 15:13 UTC

Re: [std-proposals] Type modifier to disable integer promotion

1
JS
Jan Schultke30 Mar 2025, 13:08 UTC

Re: [std-proposals] Type modifier to disable integer promotion

Note that I'm working on bringing _BitInt to C++, starting with P3639.


_BitInt does not have integer promotions, so that pretty much solves


the problem.