1

I have always, for as long as I can remember and ubiquitously, done this:

for (unsigned int i = 0U; i < 10U; ++i)
{
    // ...
}

In other words, I use the U specifier on unsigned integers. Now having just looked at this for far too long, I'm wondering why I do this. Apart from signifying intent, I can't think of a reason why it's useful in trivial code like this?

Is there a valid programming reason why I should continue with this convention, or is it redundant?

Ed King
  • 1,833
  • 1
  • 15
  • 32
  • 2
    Possible duplicate of [Meaning of U suffix](http://stackoverflow.com/questions/4380691/meaning-of-u-suffix) – Manav Dubey May 02 '17 at 14:52
  • Changed the question slightly – Ed King May 02 '17 at 14:55
  • 1
    `10` is a signed int. `10U` is an unsigned int. So maybe you are doing this to avoid implicit type conversions. In most scenarios, though (and in the example you posted, for sure), the implicit type conversions would work perfectly anyway. But if there's a way to avoid them, what harm is there in doing so? I'm just guessing. – Daniel Daranas May 02 '17 at 14:55
  • From the linked answer, it seems like it would only be useful to keep it when I think overflow might be an issue? But then again, haven't I gone some ways to mitigating for that by specifying `unsigned` in the first place, without the `U`? – Ed King May 02 '17 at 14:57
  • In [this example](http://stackoverflow.com/a/1273749/96780), that is, when you use syntactic overriding on parameter types, you'll need it, for sure. Note that I will not like your code if it uses this kind of overriding, but that is not so relevant; the important thing is that for it to work, you'll need to use the suffix if you call the overriden functions with integer literals. – Daniel Daranas May 02 '17 at 14:59
  • Thanks for the links @DanielDaranas - surprisingly difficult to find questions on this when I've never known that the `U` is just referred to as a suffix! – Ed King May 02 '17 at 15:03
  • 2
    You're welcome. There is another example, which is using them in variable definitions which use the C++11 keyword `auto`. See [this answer](http://stackoverflow.com/a/30569555/96780). (It is also not relevant that I dislike it even more than the previous one, but somehow, I feel the need to mention it.) – Daniel Daranas May 02 '17 at 15:04

5 Answers5

9

First, I'll state what is probably obvious to you, but your question leaves room for it, so I'm making sure we're all on the same page.

There are obvious differences between unsigned ints and regular ints: The difference in their range (-2,147,483,648 to 2,147,483,647 for an int32 and 0 to 4,294,967,295 for a uint32). There's a difference in what bits are put at the most significant bit when you use the right bitshift >> operator.

The suffix is important when you need to tell the compiler to treat the constant value as a uint instead of a regular int. This may be important if the constant is outside the range of a regular int but within the range of a uint. The compiler might throw a warning or error in that case if you don't use the U suffix.

Other than that, Daniel Daranas mentioned in comments the only thing that happens: if you don't use the U suffix, you'll be implicitly converting the constant from a regular int to a uint. That's a tiny bit extra effort for the compiler, but there's no run-time difference.

Should you care? Here's my answer, (in bold, for those who only want a quick answer): There's really no good reason to declare a constant as 10U or 0U. Most of the time, you're within the common range of uint and int, so the value of that constant looks exactly the same whether its a uint or an int. The compiler will immediately take your const int expression and convert it to a const uint.

That said, here's the only argument I can give you for the other side: semantics. It's nice to make code semantically coherent. And in that case, if your variable is a uint, it doesn't make sense to set that value to a constant int. If you have a uint variable, it's clearly for a reason, and it should only work with uint values.

That's a pretty weak argument, though, particularly because as a reader, we accept that uint constants usually look like int constants. I like consistency, but there's nothing gained by using the 'U'.

Scott Mermelstein
  • 15,174
  • 4
  • 48
  • 76
  • Nice explanation - confirms some things that I always take for granted. – Ed King May 02 '17 at 15:10
  • 2
    There are cases where bitshifting and integer constants don't mix 100%, and (just) compiler warnings can be mitigated by explicitly making the constants unsigned. – rubenvb May 02 '17 at 15:16
  • 2
    "The compiler might throw a warning or error in that case if you don't use the U suffix." is incorrect, at least since C99. If the literal constant can't fit in an `int`, the compiler will make it a `long` or a `long long`; only if it cannot find a signed type big enough will it produce a diagnostic. – rici May 02 '17 at 20:20
  • I recently used C# a little with arrays. The language insists that subscripts are `uint`. Another annoyance is that `byte x = 1;` works fine, but `byte y = 1+1;` is a type mismatch. Perhaps the OP had his mind damaged by C#.... – wallyk Mar 26 '18 at 18:08
4

I see this often when using defines to avoid signed/unsigned mismatch warnings. I build a code base for several processors using different tool chains and some of them are very strict.

For instance, removing the ‘u’ in the MAX_PRINT_WIDTH define below:

#define MAX_PRINT_WIDTH          (384u)
#define IMAGE_HEIGHT             (480u)   // 240 * 2
#define IMAGE_WIDTH              (320u)   // 160 * 2 double density

Gave the following warning: "..\Application\Devices\MartelPrinter\mtl_print_screen.c", line 106: cc1123: {D} warning: comparison of unsigned type with signed type

for ( x = 1; (x < IMAGE_WIDTH) && (index <= MAX_PRINT_WIDTH); x++ )

You will probably also see ‘f’ for float vs. double.

Justin J.
  • 396
  • 2
  • 12
  • 1
    This is a good point. Now that I think about it, I think I started using it all over the place precisely because of macros. – Ed King May 02 '17 at 15:36
4

I extracted this sentence from a comment, because it's a widely believed incorrect statement, and also because it gives some insight into why explicitly marking unsigned constants as such is a good habit.

...it seems like it would only be useful to keep it when I think overflow might be an issue? But then again, haven't I gone some ways to mitigating for that by specifying unsigned in the first place...

Now, let's consider some code:

int something = get_the_value();
// Compute how many 8s are necessary to reach something
unsigned count = (something + 7) / 8;

So, does the unsigned mitigate potential overflow? Not at all.

Let's suppose something turns out to be INT_MAX (or close to that value). Assuming a 32-bit machine, we might expect count to be 229, or 268,435,456. But it's not.

Telling the compiler that the result of the computation should be unsigned has no effect whatsoever on the typing of the computation. Since something is an int, and 7 is an int, something + 7 will be computed as an int, and will overflow. Then the overflowed value will be divided by 8 (also using signed arithmetic), and whatever that works out to be will be converted to an unsigned and assigned to count.

With GCC, arithmetic is actually performed in 2s complement so the overflow will be a very large negative number; after the division it will be a not-so-large negative number, and that ends up being a largish unsigned number, much larger than the one we were expecting.

Suppose we had specified 7U instead (and maybe 8U as well, to be consistent). Now it works.. It works because now something + 7U is computed with unsigned arithmetic, which doesn't overflow (or even wrap around.)

Of course, this bug (and thousands like it) might go unnoticed for quite a lot of time, blowing up (perhaps literally) at the worst possible moment...

(Obviously, making something unsigned would have mitigated the problem. Here, that's pretty obvious. But the definition might be quite a long way from the use.)

rici
  • 234,347
  • 28
  • 237
  • 341
  • Interesting. I'm happy that I have a good habit of specifying *all* integers with or without `U` as appropriate, even though I'd totally forgotten why I do it. It's nice to read a computational explanation - I wish I could mark two answers as accepted! – Ed King May 03 '17 at 08:25
  • I think this example is a strawman. The bug here is declaring "something" as a signed int, and then expecting to do unsigned arithmetic with it. The compiler will do the right thing with the literals if the variables are correctly declared. – Joshua Clayton Jun 03 '22 at 17:26
  • @joshua: It's a real bug from real code, except that in the original `count` was also an `int`. (Incorrectly, also, because it was later used as a `size_t`.) And I do note in the last paragraph that making `something` unsigned would be the solution. `7U` is just a form of defensive programming, and it is always better to correctly type all variables. Anyway, the quote is real, and so is the widespread belief that the type of a declaration somehow influences the computation of the initialiser. – rici Jun 03 '22 at 20:47
1

One reason you should do this for trivial code1 is that the suffix forces a type on the literal, and the type may be very important to produce the correct result.

Consider this bit of (somewhat silly) code:

#define magic_number(x) _Generic((x), \
                          unsigned int : magic_number_unsigned, \
                          int          : magic_number_signed \
                        )(x)

unsigned magic_number_unsigned(unsigned) {
  // ...
}

unsigned magic_number_signed(int) {
  // ...
}

int main(void) {
  unsigned magic = magic_number(10u);
}

It's not hard to imagine those function actually doing something meaningful based on the type of their argument. Had I omitted the suffix, the generic selection would have produced a wrong result for a very trivial call.


1 But perhaps not the particular code in your post.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
-1

In this case, it's completely useless.

In other cases, a suffix might be useful. For instance:

#include <stdio.h>

int
main()
{
  printf("%zu\n", sizeof(123));
  printf("%zu\n", sizeof(123LL));
  return 0;
}

On my system, it will print 4 then 8.

But back to your code, yes it makes your code more explicit, nothing more.

yoones
  • 2,394
  • 1
  • 16
  • 20
  • 2
    Actually the reason it did that was because of `LL` not `u`. the `%d` specifier is erroneous. – jiveturkey May 02 '17 at 15:09
  • I was trying to illustrate my point, not writing production-ready code... – yoones May 02 '17 at 15:14
  • Unclear why `LL` suffix is used to discuss the differences of using the `U` suffix. `LL` often causes size changes, not so often with `U`. Suggest `printf("%zu\n", sizeof(4000000000)); printf("%zu\n", sizeof(4000000000U));` to show a size difference with `U`. – chux - Reinstate Monica May 02 '17 at 16:38
  • I was talking about suffixes in general, not `U` in particular. – yoones May 02 '17 at 16:39