C Unsigned int providing a negative value?
Solution 1
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.
Solution 2
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"
.
Solution 3
%d means printf will interpret the value as an int(which is signed). use %u if it is an unsigned int.
Dannul
Updated on June 04, 2022Comments
-
Dannul almost 2 years
I have an unsigned integer but when i print it out using %d there is sometimes a negative value there?
-
unwind over 14 yearsNitpick: 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);).
-
visual_learner over 14 years@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 theva_copy
macro on systems where it isn't provided. One of them may work, but who knows which? -
LiraNuna over 14 yearsOkay 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. -
Admin over 14 yearsLiraNuna: 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.
-
Admin over 14 yearsAh, 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.
-
LiraNuna over 14 years@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.
-
Admin over 14 yearsWe 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.)
-
Johannes Schaub - litb over 14 yearsBut 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.
-
Steve Jessop over 14 yearsIt'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 :-)
-
M.M almost 5 yearsx64 ABI passes some printf arguments in registers, so any explanation involving the stack is somewhat bogus