tags:

views:

655

answers:

3

I have an unsigned integer but when i print it out using %d there is sometimes a negative value there?

+11  A: 

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".

int3
+16  A: 

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.

LiraNuna
Nitpick: C is call by value, so the compiler pulls argument values, not pointers. You don't pass pointers to values (printf("%u", ), you pass values directly (printf("%u", myvariable);).
unwind
It actually gives `printf` a pointer to the stack, though.
LiraNuna
@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
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
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.
Roger Pate
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.
Roger Pate
@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
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.)
Roger Pate
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
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
+5  A: 

%d means printf will interpret the value as an int(which is signed). use %u if it is an unsigned int.

nos