News for hackers. Stuff that matters.
Re:Using signed or unsigned int by default in C (2015) by qsort on Tuesday August 23, 2022 @01:45PM (#32568441)
Doesn't this depend?

- When iterating an array, you're supposed to use "size_t", because it's the only type that's guaranteed to contain the maximum size of an array.

- When storing the difference between two pointers, you're supposed to use "ptrdiff_t" because it's the only type that's guaranteed to contain the signed difference between two related pointers.

- When storing numbers, prefer unsigned to signed because signed overflow is UB.

Re:Using signed or unsigned int by default in C (2015) by pkhuong on Tuesday August 23, 2022 @02:52PM (#32569470)
This all makes sense at first sight, but remember that we can always take the difference between the address of an array's first element and one past the end, so you run into a lot of issues when an array (or any object) is larger than PTRDIFF_MAX bytes.

https://trust-in-soft.com/blog/2016/05/20/objects-larger-tha...

Re:Using signed or unsigned int by default in C (2015) by FartyMcFarter on Tuesday August 23, 2022 @01:57PM (#32568616)
> - When storing numbers, prefer unsigned to signed because signed overflow is UB.

There's an interesting caveat to this one - if you rely on sanitizers like ubsan to catch overflow errors, using unsigned won't work. It will happily and silently overflow.

Re:Using signed or unsigned int by default in C (2015) by Leherenn on Tuesday August 23, 2022 @03:04PM (#32569686)
For what it's worth (though you likely know it), you can add "-fsanitize=unsigned-integer-overflow" to trigger a diagnostic even if unsigned integer overflow is not UB. Of course, this only works if your code does not rely on unsigned integer overflow or if you suppress each case one by one.

I would tend to say this is a good practice to enable it, because the number of times where you rely on the overflow should be very low and well documented.

Re:Using signed or unsigned int by default in C (2015) by FartyMcFarter on Thursday August 25, 2022 @08:04AM (#32592558)
I had forgotten about that one - that's a great solution, and I agree that in most programs unsigned overflow is rarely desirable, so explicit annotation makes sense for those cases.
Re:Using signed or unsigned int by default in C (2015) by UncleMeat on Thursday August 25, 2022 @10:42AM (#32594302)
IMO the third point is backwards. Because unsigned overflow is defined you cannot detect it with tools nearly as well but it still almost certainly represents a bug in your program. Better to find the bug with ubsan or some static analyzer than silently produce broken behavior.
Re:Using signed or unsigned int by default in C (2015) by Asooka on Tuesday August 23, 2022 @03:48PM (#32570452)
Personally, I choose to just write non-standard C and turn on my compiler's option to define signed overflow as wrapping.

Note that without that option, multiplication of unsigned shorts is undefined on platforms where sizeof(unsigned short) = sizeof(int)/2. That is due to the integer promotion rules. Let's say shorts are 16-bit and ints are 32-bit, which is the case on all consumer devices. Integer promotion rules lead to both unsigned short operands being first converted to ints before multiplication. If they are both equal to 0xffff, then the result is bigger than INT_MAX, and thus undefined. Which means that just multiplying two unsigned shorts is dangerous unless you cast them to unsigned ints first. Here is a godbolt link demonstrating the problem: https://gcc.godbolt.org/z/3445PEGqY

I have never seen the benefit of leaving signed overflow undefined, so I just make it defined to avoid weird problems like that. Most people think that all unsigned arithmetic is well defined, but unfortunately that's false.

Re:Using signed or unsigned int by default in C (2015) by kevin_thibedeau on Tuesday August 23, 2022 @05:02PM (#32571460)
> I have never seen the benefit of leaving signed overflow undefined

The benefit is that architectures are free to implement it with saturating arithmetic.

Re:Using signed or unsigned int by default in C (2015) by Asooka on Wednesday August 24, 2022 @01:24PM (#32582707)
That's fine. Define it as saturating on those architectures. Just being defined as "this never happens" is hugely detrimental to predicting how you're program behaves.
Re:Using signed or unsigned int by default in C (2015) by Quekid5 on Wednesday August 24, 2022 @03:34AM (#32575998)
> I have never seen the benefit of leaving signed overflow undefined,

IIRC it affords huge optimization opportunities, esp. around loops. (Now, whether you like that or not is a value judgment, but a lot of people do want those optimizations.)

Re:Using signed or unsigned int by default in C (2015) by giomasce on Tuesday August 23, 2022 @03:26PM (#32570070)
I don't know if I am too stupid or too smart, but I use signed when some number can be negative and unsigned when it cannot. Of course I am aware of their differences other e.g. when they wrap, and act accordingly.
Re:Using signed or unsigned int by default in C (2015) by kbelder on Wednesday August 24, 2022 @01:03PM (#32582395)
Just smart enough.
Re:Using signed or unsigned int by default in C (2015) by wnoise on Tuesday August 23, 2022 @01:46PM (#32568451)
Re:Using signed or unsigned int by default in C (2015) by cannam on Tuesday August 23, 2022 @02:02PM (#32568677)
I agree with the content of this article, but all the same my advice is usually the opposite - for reasons that its author sets out rather well in the table in his follow-up article (https://blog.robertelder.org/signed-or-unsigned-part-2/)

I wrote a little piece about this myself once (http://soundsoftware.ac.uk/c-pitfall-unsigned.html)

I suppose I would loosely characterise my view as

- if your profession is "C programmer" and you really know what you're doing, you probably want to use unsigneds most of the time

- if your profession is something else, e.g. signal processing researcher who has to translate an algorithm to C or C++, you are probably better off not using unsigneds at all.

Re:Using signed or unsigned int by default in C (2015) by ghoward on Tuesday August 23, 2022 @02:09PM (#32568787)
I think I agree with you, as much as I don't want to.

I am a C programmer, and I think I do know what I am doing. (I implemented safe, UB-free two's-complement arithmetic in C using only unsigned integers.) I prefer unsigned.

But for someone who doesn't know, as long as they're not working on anything critical, signed might be "good enough".

Re:Using signed or unsigned int by default in C (2015) by cesarb on Tuesday August 23, 2022 @03:19PM (#32569942)
Reposting a comment of mine from another thread (https://news.ycombinator.com/item?id=29770689):

For me, the main reason to prefer unsigned integers whenever possible is: less special cases.

When a signed integer is used as an array index, the value can be in one of three ranges: the <0 range, the >=0 && <size range, and the >=size range. To validate the index, you need two comparisons. When an unsigned integer is used as an array index, there are only two ranges: the <size range, and the >=size range, and you need only a single comparison.

And that's not the worst situation with signed integers. From a more general point of view, there are four "classes" of signed integer: positive (>0), zero, negative (<0), and INT_MIN. Everybody tends to forget about that last one, but it's "special" in that it can break things in unexpected ways. Negating it doesn't work (you'd expect negating any number less than zero to result in a number greater than zero, but for INT_MIN that doesn't happen). Dividing it can trap (see for instance https://kqueue.org/blog/2012/12/31/idiv-dos/ which has a couple of examples) or worse.

With unsigned integers, there are only two "classes", zero and non-zero, and it's common to not even need special treatment for zero, reducing the whole thing to a single "class" of values.

Re:Using signed or unsigned int by default in C (2015) by jcelerier on Wednesday August 24, 2022 @04:13AM (#32576275)
> When a signed integer is used as an array index, the value can be in one of three ranges: the <0 range, the >=0 && <size range, and the >=size range. To validate the index, you need two comparisons. When an unsigned integer is used as an array index, there are only two ranges: the <size range, and the >=size range, and you need only a single comparison.

but the need for the <= 0 case does not disappear - it's a property of integers (Z) whether you want it or not, and the very second you do an arithmetic operation such as a - b, you expect this to behave like numbers:

    void compute(int* array, size_t len, /* any integral type */ x) {
      size_t res = len - x;
      if(res < len)
        printf("%d", array[res])
    }

this code is wrong an awful lot of time because there isn't actually "a single range" just because the integer is unsigned - you have to make sure that `len >= x` if you want a correct result so there will be comparisons there instead, but those are much trickier to get right from my experience finding bugs in such code.

and if you are going to say that "this rarely happens" - here is an excerpt of a set of simple cases I could find just by grepping on the projects I have cloned where using unsigned will cause crashes: https://pastebin.com/sTgGPV9k

Re:Using signed or unsigned int by default in C (2015) by reltuk on Tuesday August 23, 2022 @01:21PM (#32568075)
Similar arguments are also seen in https://graphitemaster.github.io/aau/.

When using unsigned ints for backward iteration, I'm partial to looping as:

  for (i = size - 1; i < size; i--) {
    ...
  }
since it has so much symmetry with forward iteration.
Re:Using signed or unsigned int by default in C (2015) by 10000truths on Tuesday August 23, 2022 @01:27PM (#32568172)
I would rather just use a plain for loop and manipulate the index in the loop body:

  for(uint32_t i = 0; i < length; ++i) {
      i = (length - 1) - i;
      // ...
  }
Much easier for me to understand, making it less likely to mess anything up.
Re:Using signed or unsigned int by default in C (2015) by edflsafoiewq on Tuesday August 23, 2022 @01:32PM (#32568239)
You'll need a new variable there, but otherwise yeah.
Re:Using signed or unsigned int by default in C (2015) by WalterBright on Tuesday August 23, 2022 @03:07PM (#32569725)
Even easier (for D):

    foreach (i; 0 .. length)
D takes care of selecting the correct type for `i`.
Re:Using signed or unsigned int by default in C (2015) by phkahler on Tuesday August 23, 2022 @01:38PM (#32568319)
I'd argue that is a terrible way to write it since it depends on the rollover to terminate. Using i >= 0 is less mental work but also requires that i be signed.
Re:Using signed or unsigned int by default in C (2015) by ghoward on Tuesday August 23, 2022 @01:40PM (#32568370)
Rollover on unsigned ints is well-defined in C.
Re:Using signed or unsigned int by default in C (2015) by hbn on Tuesday August 23, 2022 @03:36PM (#32570240)
I think their point is that it's less well defined in the average human's brain

When most people see 0 - 1 they don't immediately think 11111111111111111111111111111111

Re:Using signed or unsigned int by default in C (2015) by ghoward on Tuesday August 23, 2022 @05:09PM (#32571551)
We're talking about C, though. I hope the average human is not writing C.
Re:Using signed or unsigned int by default in C (2015) by jcelerier on Wednesday August 24, 2022 @04:17AM (#32576313)
the average person writing C is absolutely an average human in terms of relationship with mathematics
Re:Using signed or unsigned int by default in C (2015) by xdavidliu on Tuesday August 23, 2022 @01:48PM (#32568484)
if we used i >= 0 and someone were to come in and change "int i" to "unsigned i" or "size_t i", the result would be catastrophic
Re:Using signed or unsigned int by default in C (2015) by Leherenn on Tuesday August 23, 2022 @03:07PM (#32569739)
The same argument can be applied to GP's code with the added bonus it will cause UB at some point.
Re:Using signed or unsigned int by default in C (2015) by JonChesterfield on Tuesday August 23, 2022 @08:58PM (#32573722)
`for (unsigned i = n; i-->0;) {}`

Probably formatted i-- > 0. Concise and reads (once used to it anyway) something like i decrementing to zero.

Re:Using signed or unsigned int by default in C (2015) by DrBurrito on Wednesday August 24, 2022 @11:52AM (#32581076)
The argument against unsigned is that people abuses unsigned as a way of false safety, as a form of assert. They think the number cannot go below zero or above maxvalue. But in practice it can under- and overflow, so this is a bogus assert. I think there is a valid point in this.

So, if someone does x=(0-1), signed will contain (-1) and unsigned will contain (MAXVALUE) (255 if x is char, 8 bits). The point being that (-1) is clearly wrong and invalid, and 255 is valid but wrong. The price to pay for this is one bit of reduced range (meaning, reducing the range by half).

Now, all modern processors have under- and overflow checks. It is also true that nobody uses them regularly, and that they are not easily accessible in C.

Therefore: use unsigned only for modulo arithmetic. For the rest, used signed numbers, as they behave like you would expect.

Also, the C++ Core Guidelines: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC... https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...

Re:Using signed or unsigned int by default in C (2015) by purpleblue on Tuesday August 23, 2022 @01:49PM (#32568510)
The mathematical definition of "integer" includes the set of negative integers. That's the whole point, otherwise we could just use natural numbers. So making ints signed makes the most sense otherwise there's an impedance mismatch that you need to explain away.
Re:Using signed or unsigned int by default in C (2015) by mcguire on Tuesday August 23, 2022 @02:35PM (#32569181)
The mathematical definition of "integer" is unbounded above and below.

The "numbers" used in computing systems are not mathematical numbers in any way.

Re:Using signed or unsigned int by default in C (2015) by Asooka on Tuesday August 23, 2022 @03:34PM (#32570220)
The numbers used in computing systems are normal mathematical numbers in the Z_2^32 field. The signed ones are shifted by half the range in the negative direction. There is nothing un-mathematical about them, people who have studied any math in university, i.e. all CS graduates, should have gone through an introductory algebra course that covers fields, rings, etc. So I'm not sure why people keep saying ints are not mathematical.
Re:Using signed or unsigned int by default in C (2015) by mcguire on Tuesday August 23, 2022 @04:11PM (#32570805)
To be honest, I adapted a phrase I usually use for floating point numbers.

But anyway, "So making ints signed makes the most sense otherwise there's an impedance mismatch that you need to explain away" is a pretty poor argument when you're dealing with Z_2^32 (or 2^64) minus 2^31, with some operations becoming partial. (And that's assuming you're on a twos-complement machine; those goofy ones-complement boxes had positive and negative zero.)

Re:Using signed or unsigned int by default in C (2015) by tsimionescu on Tuesday August 23, 2022 @04:05PM (#32570715)
That depends on the computing system. You're right if we're talking about the processor level (on any modern processor), but the "signed ints" in C or C++ are not a field at all, since INT_MAX + 1 is undefined, as are -INT_MIN and INT_MIN - 1 (and many many many multiplications). Also, as someone else was pointing out, unsigned short arithmetic is not well defined either.
Re:Using signed or unsigned int by default in C (2015) by qsort on Tuesday August 23, 2022 @04:51PM (#32571325)
I know what you mean and I'm not saying this with any animus, but this is pretty funny:

> people who have studied any math in university, i.e. all CS graduates, should have gone through an introductory algebra course that covers fields, rings, etc.

> Z_2^32 field

Re:Using signed or unsigned int by default in C (2015) by jcelerier on Wednesday August 24, 2022 @04:21AM (#32576359)
> The mathematical definition of "integer" is unbounded above and below.

which is exactly why signed overflow is UB: if you use int, you say "I want something that behaves exactly like a mathematical integer in exchange of the promise of not working with quantities too large"

Re:Using signed or unsigned int by default in C (2015) by andreareina on Wednesday August 24, 2022 @09:17AM (#32579063)
That's the first time I've heard that reason for int overflow being UB, do you have a source for that?
Re:Using signed or unsigned int by default in C (2015) by jcelerier on Thursday August 25, 2022 @03:24AM (#32590674)
how do you call something that verifies those as axioms? https://gcc.godbolt.org/z/53ben65hf
Re:Using signed or unsigned int by default in C (2015) by qsort on Tuesday August 23, 2022 @02:57PM (#32569555)
I mean, it's not the only word in programming that's overloading a word with a mathematical definition. Just off the top of my head:

- function

- set

- map

- monad

- vector

- field

- class

Some of them are obviously referring to something else entirely. Some of them are kind of like the math thing but subtly different.

Re:Using signed or unsigned int by default in C (2015) by jpfr on Wednesday August 24, 2022 @07:03AM (#32577716)
Tensor.

The term is used to mean “multi-dimensional array” in the machine learning community.

That is however not a tensor.

Re:Using signed or unsigned int by default in C (2015) by benj111 on Tuesday August 23, 2022 @02:12PM (#32568842)
But neither signed or unsigned ints can represent all ints. It's a question of what subset of ints you want to be able to represent.
Re:Using signed or unsigned int by default in C (2015) by pornel on Tuesday August 23, 2022 @02:28PM (#32569074)
Integers can also be infinitely large. C doesn't use mathematical definitions, but its own.
Re:Using signed or unsigned int by default in C (2015) by simonblack on Tuesday August 23, 2022 @07:09PM (#32572795)
FWIW, I find myself using unsigned ints more often today than I used to.

Even more so, I find myself using particular sizes of unsigned ints (uint8_t, uint16_t, etc) rather than the default "unsigned int"

Re:Using signed or unsigned int by default in C (2015) by dvh on Tuesday August 23, 2022 @02:18PM (#32568923)
I hate that stdint.h (or whoever) defines those types as uint8_t instead of simply uint8. Why was the _t necessary?
Re:Using signed or unsigned int by default in C (2015) by pornel on Tuesday August 23, 2022 @02:23PM (#32568994)
A shorter name probably broke someone's code in 1998.

_t acts as a namespace, and that's all namespacing you can get in C.

Re:Using signed or unsigned int by default in C (2015) by cesarb on Tuesday August 23, 2022 @03:13PM (#32569829)
Calling it just "uint8" could conflict with software which already used it as an identifier, or worse, a macro; on the other hand, names ending with _t are reserved (see for instance https://www.gnu.org/software/libc/manual/html_node/Reserved-...), so they could be used by the standard for these new types.
Re:Using signed or unsigned int by default in C (2015) by mytailorisrich on Tuesday August 23, 2022 @02:34PM (#32569159)
The convention '_t' is to unambiguously indicate that the name is a type.

Some people also use '_e' for enums, etc.

Re:Using signed or unsigned int by default in C (2015) by qsort on Tuesday August 23, 2022 @03:08PM (#32569749)
The _t suffix is reserved for types defined by the standard. Although this is an excess of pedantry, strictly speaking you should not be defining names ending in _t.
Re:Using signed or unsigned int by default in C (2015) by mytailorisrich on Tuesday August 23, 2022 @03:25PM (#32570061)
By 'the standard' do you mean POSIX? Or has that been added to a C standard?

Either way, in general I'd agree this is an excess of pedantry and I don't really see an issue with using _t for types if that works for you.

Re:Using signed or unsigned int by default in C (2015) by qsort on Tuesday August 23, 2022 @03:40PM (#32570313)
I wasn't sure, I just checked.

POSIX reserves everything ending in _t. C99 and later reserve identifiers starting with "int" or "uint" and ending in "_t".

Source: https://en.cppreference.com/w/c/language/identifier

Re:Using signed or unsigned int by default in C (2015) by Someone on Tuesday August 23, 2022 @05:20PM (#32571691)
For those wondering: that phrase has to be read as “C99 and later reserve identifiers ((starting with "int" or "uint") and ending in "_t")”, not as “C99 and later reserve identifiers starting with "int" or "uint" and identifiers ending in "_t"”

It’s not as if a program with a variable called interest_rate or ford_model_t would be nonconforming according to the standard.

Re:Using signed or unsigned int by default in C (2015) by alerighi on Tuesday August 23, 2022 @04:26PM (#32571001)
While this is true, I don't see either a reason to use _t in your code. Since it's your code, you don't have the problem for which the _t suffix was introduced, that is to avoid conflicts that can break other people code. You don't either get any benefit of using the _t suffix, since it's obvious if something is a type or not, especially nowadays (just look at the syntax coloring). You don't even need the _t to distinguish for example between a struct, enum or union definition and it's relative typedef:

    typedef struct MyStruct { ... } MyStruct;
is perfectly valid, and in my opinion better than:

    typedef struct MyStruct_s { ... } MyStruct_t;
Where the suffix _s and _t doesn't add anything useful but only complicate the code for nothing.
Re:Using signed or unsigned int by default in C (2015) by virtualritz on Wednesday August 24, 2022 @05:15AM (#32576816)
Re:Using signed or unsigned int by default in C (2015) by jasonhansel on Tuesday August 23, 2022 @02:42PM (#32569307)
-fwrapv
Re:Using signed or unsigned int by default in C (2015) by w0mbat on Tuesday August 23, 2022 @01:10PM (#32567914)
Repost from 2015
Re:Using signed or unsigned int by default in C (2015) by coding123 on Tuesday August 23, 2022 @01:32PM (#32568241)
use longs because it's not arch dependent
Re:Using signed or unsigned int by default in C (2015) by xdavidliu on Tuesday August 23, 2022 @01:49PM (#32568503)
long in C and C++ is absolutely arch dependent. In Java it's not depedendent, but neither are any of the other primitives in Java.
Re:Using signed or unsigned int by default in C (2015) by messe on Tuesday August 23, 2022 @02:21PM (#32568964)
long is definitely arch dependent.

It’s even operating system dependent:

It’s 32-bits on 32-bit x86 unix-likes and windows, as well as 32-bit on 64-bit windows.

On 64-bit unix-likes it’s 64-bit.

Embedded is so varied (and generally 16 or 32 bit), that I’m not even go to hazard a guess on the distribution there.

Re:Using signed or unsigned int by default in C (2015) by acuozzo on Tuesday August 23, 2022 @01:52PM (#32568539)
long is only guaranteed by to be a minimum of 32 bits.

It's 64 on Tru64 UNIX systems, for instance.