I have an unsigned integer but when i print it out using %d there is sometimes a negative value there?
-
2See if your compiler has an option to warn about this kind of error. It's -Wformat with gcc. – Dec 02 '09 at 10:16
-
Possible duplicate of [How can I print maximum value of an unsigned integer?](http://stackoverflow.com/questions/12812812/how-can-i-print-maximum-value-of-an-unsigned-integer) – phuclv Dec 07 '16 at 01:47
3 Answers
Printing %d
will read the integer as a signed decimal number, regardless of its defined type.
To print unsigned numbers, use %u
.
This happens because of C's way to handle variable arguments. The compiler just pulls values from the stack (typed as void*
and pointing to the call stack) and printf
has to figure out what the data contains from the format string you give it to.
This is why you need to supply the format string - C has no way of RTTI or a 'base class' (Object
in Java, for example) to get a generic or predefined toString
from.

- 79,187
- 7
- 161
- 281

- 64,916
- 15
- 117
- 140
-
4Nitpick: C is call by value, so the compiler pulls argument values, not pointers. You don't pass pointers to values (printf("%u", &myvariable);), you pass values directly (printf("%u", myvariable);). – unwind Dec 02 '09 at 09:44
-
@LiraNuna - The implementation of varargs functions isn't specified, which is why neither `#define va_copy(dest, src) dest = src` or `#define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))` is a portable replacement for the `va_copy` macro on systems where it isn't provided. One of them may work, but who knows which? – Chris Lutz Dec 02 '09 at 09:53
-
Okay then, "most commonly implemented by ...". There isn't really another effective way to move an unknown amount of data where each of the arguments has a variable size... a pointer is a constant size and the compiler already has the size information from the caller. `va_copy` is an intrinsic aswell. – LiraNuna Dec 02 '09 at 09:58
-
LiraNuna: Sure there is, push it (in the sense of asm push instructions) to the stack. va_copy doesn't have to be an intrinsic, it does have to know implementation details which vary across implementations. – Dec 02 '09 at 10:14
-
Ah, I see that if you stretch "pass a pointer to the stack" to mean the register that indicates the current stack frame, you'd be right, but that's too much of a stretch. – Dec 02 '09 at 10:22
-
@Roger: Yes, push it - and then provide printf with the pointer to the the location of the argument on the stack - since the argument is of dynamic size. I don't get why you argue about something we agree. English is not my native language, so I'm sorry if there's misunderstanding. – LiraNuna Dec 02 '09 at 10:27
-
We don't agree. How many "pointers" do you think printf gets for printf(s, a, b, c)? Saying the stack is "provided by a pointer" is enough of a stretch to be considered plain wrong---at that point you're not writing C. (Certainly could be a language issue.) – Dec 02 '09 at 10:37
-
But this is how every function call behaves that doesn't use registers. It's not something specific to printf or vararg functions, actually. The stack frame of the current function starts somewhere, and there, or directly below it, will be the incoming arguments, on many architectures anyway. – Johannes Schaub - litb Dec 02 '09 at 11:08
-
It's implementation-dependent whether there's a stack at all. Arguments just are. In practice (as LiraNuna says and everyone else very well knows) almost every calling convention you will ever encounter has a means of passing a stack *pointer*, even if it's by the CPU itself having a dedicated register only for that purpose. It's not necessarily the case that all arguments are passed on the stack - some calling conventions pass the first few in registers. However, it's a PITA implementing varargs with such a calling convention, so I would not blame anyone who puts all varargs on stack :-) – Steve Jessop Dec 02 '09 at 15:45
-
x64 ABI passes some printf arguments in registers, so any explanation involving the stack is somewhat bogus – M.M Aug 19 '19 at 02:05
This should work:
unsigned int a;
printf("%u\n", a);
Explanation: On most architectures, signed integers are represented in two's complement. In this system, positive numbers less than 2**(N-1)
(where N = sizeof(int)
) are represented the same way regardless whether you are using an int
or a unsigned int
. However, if the number in your unsigned int is larger than 2**(N-1)
, it represents a negative signed number under two's complement -- which is what printf
gave you when you passed it "%d"
.

- 12,861
- 8
- 51
- 80
-
I don't know for C, but in C++ I'd say it's undefined behavior. The problem is: as soon as you give an explanation for the undefined behavior, people will remember it and rely on it. But you can't. We don't only have Intel, we don't only have 32 bit. We have ARM, we have Arduinos and other microcontrollers, we have 8 bit, 64 bit and whatever. In the end, it's just undefined behavior - we don't know what will happen, including that the compiler might optimize it away because it recognized that it is undefined behavior – Thomas Weller Dec 15 '22 at 15:08
%d means printf will interpret the value as an int(which is signed). use %u if it is an unsigned int.

- 223,662
- 58
- 417
- 506