4

code:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]) {
    printf("%lu\n%lu\n%lu\n%lu\n%lu\n%lu\n%lu\n",
        UINT32_MAX,
        UINT32_MAX,
        UINT32_MAX,
        UINT32_MAX,
        UINT32_MAX,
        UINT32_MAX,
        UINT32_MAX);
    return 0;
}

output:

4294967295
4294967295
4294967295
4294967295
4294967295
18446744073709551615
18446744073709551615

bug or intentional? and why? i think it speaks for itself but the interface needs me to add more lines before i can post it (to much code for to less text lol)

Matombo
  • 77
  • 1
  • 9
  • 1
    Your `printf` formats don't match the values you're passing. Your compiler should have warned about this. Because you're passing unexpected argument types, they are being unpacked incorrectly by `printf`. – Tom Karzes Feb 17 '16 at 13:04
  • 1
    If you're using GCC or Clang, it's a good practice to add these flags when compiling `-Wall -Wextra`. Make this an habit. – jweyrich Feb 17 '16 at 13:05

3 Answers3

15

You are using %lu, this is incorrect. The %lu specifier is for unsigned long and only unsigned long, not uint32_t. This is why the output is incorrect. Use PRIu32 instead.

Your compiler should have caught this error for you, if you were compiling with warnings enabled.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> // defines PRIu32

printf(
    "%" PRIu32 "\n"
    "%" PRIu32 "\n"
    "%" PRIu32 "\n"
    "%" PRIu32 "\n"
    "%" PRIu32 "\n"
    "%" PRIu32 "\n"
    "%" PRIu32 "\n",
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX);

In practice, PRIu32 is defined to "u" on most systems.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 1
    An alternative would be to continue using `%lu`, and to use `(unsigned long)UINT32_MAX`. This may be useful if you cannot use `` for some reason. – Ian Abbott Feb 17 '16 at 15:32
  • 1
    @Ian Abbott Need to add: casting to `(unsigned long)` is a good alternative because `unsigned long` is _at least_ the width of `uint32_t`. – chux - Reinstate Monica Feb 17 '16 at 16:22
3

This is undefined behavior: you are passing unsigned int, but your %lu format tells printf that you are passing long unsigned int. This leads to undefined behavior, because printf goes by what the format specifier says (in fact, it has no other way to find out, because type information is not passed to printf).

Once you fix your format issue, the problem goes away:

printf("%u\n%u\n%u\n%u\n%u\n%u\n%u\n",
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX,
    UINT32_MAX);

This prints

4294967295
4294967295
4294967295
4294967295
4294967295
4294967295
4294967295

Demo.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1
$ gcc -Wall -Wextra your_code.c
warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘unsigned int’

It's not a long, don't use the l specifier.

Your code has Undefined Behaviour, and in practice it essentially reads garabage.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • It's not an `unsigned long`, but it's not an `unsigned int` either, so merely omitting the `l` is incorrect. – Ian Abbott Feb 18 '16 at 11:22
  • Yes, technically the minimum size for `int` is 2 bytes. Finding such a system can be tricky though ;) – Karoly Horvath Feb 18 '16 at 11:31
  • @IanAbbott (replying to myself) - However, I _think_ the type of the constant `UINT32_MAX` will always be one of `unsigned int` or `unsigned long`, rather than something inbetween, so one of `%u` or `%lu` would work, but the problem is knowing which one. Hence the need for the `PRIu32` macro from ``. – Ian Abbott Feb 18 '16 at 11:34
  • I think `int` is typically 2 bytes on C compilers for 16-bit systems, such as MS-DOS (without any 32-bit extensions). – Ian Abbott Feb 18 '16 at 11:47
  • @IanAbbott: pretty much what I was saying... but who knows, perhaps MS-DOS is popular in the area you live in. – Karoly Horvath Feb 18 '16 at 11:53