Live data from Hacker News

Summary of C/C++ integer rules

nayuki.io

11–20 of 98 posts

Re: Summary of C/C++ integer rules

#11

[Dons language lawyer hat] > floating-point number types will not be discussed at all, because that mostly deals with how to analyze and handle approximation errors that stem from rounding. By contrast, integer math is a foundation of programming and computer science, and all calculations are always exact in theory (ignoring implementations issues like overflow). Integer overflow is no mere implementation issue, any…

Signed overflow is undefined behavior.

Re: Summary of C/C++ integer rules

#12
post #3

It’s funny that you would end up with a similar conclusion for other parts of the language (e.g. operators) as well. Just a gigantic set of inane rules everywhere causing you to constantly be in danger of introducing bugs and portability issues.

But! And that's important -- it allows for great performance, so you can make ten/hundred times more mistakes per second than in other, "safer" languages.

Nowadays, it doesn't provide any performance gain. I didn't see those days but maybe it was important for performance back in 70s/80s/90s even it was risky? e.g null terminated string was chosen due to low space overhead.

Re: Summary of C/C++ integer rules

#13
In the myths section:

> char is always 8 bits wide. int is always 32 bits wide

> Signed overflow is guaranteed to be wrap around. (e.g. INT_MAX + 1 == INT_MIN.)

Are there any current, relevant hardware architectures where this is not true (e.g. bytes are not 8 bits, and integers are not 2's complement)?

E.g. what's the point of "portability" if there is no physical hardware around anymore where those restrictions would apply?

Re: Summary of C/C++ integer rules

#14
post #12
post #3

Earlier quoted context omitted.

But! And that's important -- it allows for great performance, so you can make ten/hundred times more mistakes per second than in other, "safer" languages.

Nowadays, it doesn't provide any performance gain. I didn't see those days but maybe it was important for performance back in 70s/80s/90s even it was risky? e.g null terminated string was chosen due to low space overhead.

It depends on what you are doing. For some kinds of programs, C/C++ are going to be much faster than most "modern" languages.

Re: Summary of C/C++ integer rules

#15

> Having signed and unsigned variants of every integer type essentially doubles the number of options to choose from. This adds to the mental burden, yet has little payoff because signed types can do almost everything that unsigned ones can. Unsigned types are quite useful when doing bit twiddling because they don't overflow or have a bit taken up by the sign.

> Unsigned types are quite useful when doing bit twiddling because they don't overflow or have a bit taken up by the sign.

That's essentially their only application. The rest are stupid single-bit memory-size optimizations. As Jens Gustedt noted, it's one of the (many) misnomers in the C language. It should be better called "modulo" instead of "unsigned". Other such misnomers that I recall:

    unsigned -> modulo
    char     -> byte
    union    -> overlay
    typedef  -> typealias
    const    -> immutable
    inline   -> negligible
    static   -> intern
    register -> addressless
EDIT: found the reference https://gustedt.wordpress.com/2010/08/18/misnomers-in-c/

Re: Summary of C/C++ integer rules

#16

In the myths section: > char is always 8 bits wide. int is always 32 bits wide > Signed overflow is guaranteed to be wrap around. (e.g. INT_MAX + 1 == INT_MIN.) Are there any current, relevant hardware architectures where this is not true (e.g. bytes are not 8 bits, and integers are not 2's complement)? E.g. what's the point of "portability" if there is no physical hardware around anymore where those restrictions wou…

Signed integers wrapping and 2’s complement are separate issues. C++20 specifies that signed integer are 2’s complement, but signed overflow is still undefined.

Re: Summary of C/C++ integer rules

#17

[Dons language lawyer hat] > floating-point number types will not be discussed at all, because that mostly deals with how to analyze and handle approximation errors that stem from rounding. By contrast, integer math is a foundation of programming and computer science, and all calculations are always exact in theory (ignoring implementations issues like overflow). Integer overflow is no mere implementation issue, any…

> char, signed char, and unsigned char are distinct types, but that's only true of char.

That's correct, I was going to bring that up too.

This is particularly important because char and unsigned char are special in that they are an exception the aliasing rules. That is, in this function:

    float foo(char* cp, float* fp) {
        *fp = 7;
        return *(float*)cp;
    }
    /* ... */
    float f = 2;
    float g = foo((char*)&f, &f);
Then g should end up equal to 7. That's true even if you change the type of the cp parameter to const char*! If you change "char" to "unsigned char" in both places then its behaviour stays the same, but if you change it to "signed char" in both places then it has undefined behaviour (if I've remembered everything correctly). Now I think about it, this conflation of char's use in the C standard has probably prevented a lot of optimisations where code was just using char* for strings rather than for potential aliasing.

Another point, which is very related, is that uint8_t and int8_t do not necessarily have to be a typedef for unsigned char / signed char or char, even if char is 8 bits wide. So you could end up with (at least) 5 types that are 8-bit wide!

Combined with the above aliasing rules only applying to char and unsigned char, that means you cannot reliably expect uint8_t to have that aliasing exception. Indeed, gcc originally made a new type of uint8_t and int8_t but that caused so many bugs that they ended up switching them to unsigned char and char (and I think Visual Studio has always done so).

> > Character literals (in single quotes) have the type (signed) int in C, but (signed or unsigned) char in C++.

> That's not correct. In C++, the type of a character literal is simply char, never signed char nor unsigned char.

I was going to bring this up too, although I wouldn't quite say it's outright incorrect because I'm not sure they were making the claim you think they were - it could be interpreted to mean that it's always char in C++ but by the way don't forget that could be a signed or unsigned type (note the lack of monospace font for their use of "signed" and "unsigned"). But probably best not to overanalyse it since they probably didn't know the types were distinct - the main thing is reiterate, as you've done, that it's always `char` regardless of whether that's signed or unsigned.

Re: Summary of C/C++ integer rules

#18
post #14
post #12

Earlier quoted context omitted.

Nowadays, it doesn't provide any performance gain. I didn't see those days but maybe it was important for performance back in 70s/80s/90s even it was risky? e.g null terminated string was chosen due to low space overhead.

It depends on what you are doing. For some kinds of programs, C/C++ are going to be much faster than most "modern" languages.

I didn't mean C is not fast or not faster than other languages. It's still the fastest one I believe.

What I meant is undefined behaviors allow compilers to optimize in a way that would not be possible otherwise. So, it might be a deliberate decision back then, to leverage performance. I don't know, just an idea.

Re: Summary of C/C++ integer rules

#19

In the myths section: > char is always 8 bits wide. int is always 32 bits wide > Signed overflow is guaranteed to be wrap around. (e.g. INT_MAX + 1 == INT_MIN.) Are there any current, relevant hardware architectures where this is not true (e.g. bytes are not 8 bits, and integers are not 2's complement)? E.g. what's the point of "portability" if there is no physical hardware around anymore where those restrictions wou…

Remember to add: that can actually run standard C++ (i.e. with exceptions)?

Certainly you can find an architecture which may run some type of C-like language with strange arithmetic rules (e.g. DSPs). I would bet it's harder to find one such architecture where one can run standard C, and impossible to find one which can run standard C++.

Re: Summary of C/C++ integer rules

#20

In the myths section: > char is always 8 bits wide. int is always 32 bits wide > Signed overflow is guaranteed to be wrap around. (e.g. INT_MAX + 1 == INT_MIN.) Are there any current, relevant hardware architectures where this is not true (e.g. bytes are not 8 bits, and integers are not 2's complement)? E.g. what's the point of "portability" if there is no physical hardware around anymore where those restrictions wou…

DSP's have often uncommon sizes. tms320c5502 for example has following sizes: char-- 16 bits short --16 bits int --16 bits long-- 32 bits long long -- 40 bits float-- 32 bits double -- 64 bits
Post reply on HN