Live data from Hacker News

Summary of C/C++ integer rules

nayuki.io

71–80 of 98 posts

Re: Summary of C/C++ integer rules

#71

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

> long long -- 40 bits

Isn't this in direct contradiction to what the article says?

> long long: At least 64 bits, and at least as wide as long.

Re: Summary of C/C++ integer rules

#72
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.

> it allows for great performance, so you can make ten/hundred times more mistakes per second than in other, "safer" languages. This is false. For a long time C performance used to be inferior to Fortran, which is arguably safer than C. It's hilarious that the strict aliasing and `restrict` keyword was born out of making C on par with Fortran and UB became a major issue to C programmers as a result!

Yes, that's why C has undefined behavior. Absolutely

Re: Summary of C/C++ integer rules

#73

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…

Those are two different things:

For 'char has 8 bits': the bitwidth is 'implementation defined' in C. If you know your target architectures, you can assume it's 8 bits, because it's indeed a question of portability.

For 'int must not overflow': this is 'undefined behaviour' in C. You must not do it, regardless of what you know about your target architectures, because this is a language level prohibition.

Re: Summary of C/C++ integer rules

#74

Earlier quoted context omitted.

> No need to enforce your semantics through type Maybe I'm spoiled by other languages with more powerful type systems, but this is exactly what I want my types to do! Isn't this why we have type traits and concepts and whatnot in C++ now? If not for semantics, why have types at all, the compiler could figure out what amount of bytes it needs to store my data in, after all. I use types for two things: to map semantics…

But "unsigned" doesn't actually enforce the semantics you want. Missing an overflow check means your value will never be negative, but it is almost certainly still a bug. And because unsigned overflow is defined, the compiler isn't allowed to prevent you from doing it! This is just enough type semantics to injure oneself.

So, because its not perfect, should you throw it all out?

Re: Summary of C/C++ integer rules

#75
post #59

[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…

> This is no longer true of C++. As of C++20, signed integer types are defined to use two's complement. [0] I don't think C intends to do the same. As no good language lawyer discussion should be free from pedantry, there is no such thing as "As of C++20". C++20 is just a new version of the C++ standard. Projects that target C++11 or C++14 or C++17 are all still here and won't go away any time soon, and the respectiv…

> C++20 is just a new version of the C++ standard.

and per ISO rules, older versions are withdrawn (as can be confirmed for C++ here: https://www.iso.org/standard/79358.html) and not to be used anymore: https://www.iso.org/files/live/sites/isoorg/files/store/en/P...

    Other reasons why a committee may decide to propose a standard for withdrawal include the following :
    ▸ ▸ the standard does not reflect current practice or research
    ▸ ▸ it is not suitable for new and existing applications (products,
    systems or processes)
    ▸ ▸ it is not compatible with current views and expectations
    regarding quality, safety and the environment

Re: Summary of C/C++ integer rules

#76

Earlier quoted context omitted.

Positive values are a particular case of signed values, you can still use signed ints to store positive values. No need to enforce your semantics through type, and especially not when the values of the type are trivially particular cases of the values of another type. For example, when you write a function in C that computes prime factors of an int, do you need a type for prime numbers? No, you just use int. The same…

> No need to enforce your semantics through type Maybe I'm spoiled by other languages with more powerful type systems, but this is exactly what I want my types to do! Isn't this why we have type traits and concepts and whatnot in C++ now? If not for semantics, why have types at all, the compiler could figure out what amount of bytes it needs to store my data in, after all. I use types for two things: to map semantics…

> Maybe I'm spoiled by other languages with more powerful type systems, but this is exactly what I want my types to do! Isn't this why we have type traits and concepts and whatnot in C++ now? If not for semantics, why have types at all, the compiler could figure out what amount of bytes it needs to store my data in, after all.

yes, but understand that, despite the name, what unsigned models in C / C++ is not "positive numbers" but "modulo 2^N" arithmetic (while signed models the usual arithmetic).

There is no good type that says "always positive" by default in C or C++ - any type which gives you an infinite loop if you do

    for({int,unsigned,whatever} i = 0; i 
is not a good type.

If you want a "always positive" type use some safe_int template such as https://github.com/dcleblanc/SafeInt - here if you do "x - y" and the result of the computation should be negative, then you'll get the rightful runtime error that you want, not some arbitrarily high and incorrect number

The correct uses of unsigned are for instance for computations of hashes, crypto algorithms, random number generation, etc... as those are in general defined in modular arithmetic

Re: Summary of C/C++ integer rules

#77

Earlier quoted context omitted.

> 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 ->…

> That's essentially their only application. What about when it doesn't make semantic sense to have negative values? Eg for counting things, indexing into a vector, size of things. If negative doesn't make sense, I use unsigned types. Its not about the memory-size in that case.

While I also like to use unsigned numbers when that is the correct type of a variable, the C language does not really have support for unsigned integers.

As someone else already said, the so called "unsigned" integers in C are in fact remainders modulo 2^N, not unsigned integers.

While the sum and the product of 2 unsigned integers is also an unsigned integer, the difference of 2 unsigned integers is a signed integer.

The best behavior for a programming language would be to define correctly the type of the difference of 2 unsigned integers and the second best behavior would be to specify that the type of the result is unsigned, but to insert automatically checks for out-of-domain results, to detect the negative results.

As C does not implement any of these behaviors, whenever using unsigned integers you must either not use subtraction or always check for negative results, unless it is possible to always guarantee that negative results cannot happen.

This is a source of frequent errors in C when unsigned integers are used.

The remainders modulo 2^N can be very useful, so an ideal programming language would support signed integers, unsigned integers and modular numbers.

Re: Summary of C/C++ integer rules

#78

> 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 ->…

Thanks for this, gonna add some #defines to my headers :)

Re: Summary of C/C++ integer rules

#79

[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…

What is the reference to "Dons"?

Re: Summary of C/C++ integer rules

#80

Earlier quoted context omitted.

> No need to enforce your semantics through type Maybe I'm spoiled by other languages with more powerful type systems, but this is exactly what I want my types to do! Isn't this why we have type traits and concepts and whatnot in C++ now? If not for semantics, why have types at all, the compiler could figure out what amount of bytes it needs to store my data in, after all. I use types for two things: to map semantics…

> Maybe I'm spoiled by other languages with more powerful type systems, but this is exactly what I want my types to do! Isn't this why we have type traits and concepts and whatnot in C++ now? If not for semantics, why have types at all, the compiler could figure out what amount of bytes it needs to store my data in, after all. yes, but understand that, despite the name, what unsigned models in C / C++ is not "positiv…

+1 for this. I was just bitten by this last week, when I switched from using a custom container where size() was an int to a std::vector where size() is size_t.

The code was check-all-pairs, e.g.

  for (int i = 0; i 
Which worked just fine for int size, but failed spectacularly for size_t size when size==0.

I totally should have caught that one, but I just couldn't see it until someone else pointed it out. And then it was obvious, like many bugs.

Post reply on HN