views:

833

answers:

10

in c, i tried to print out address of variable and address of some function. I got one is negative value, the other is positive value. My question is: why does C not represent in all negative or all positive value?

Here is my code:

int foo() { 
     return 0;
}

int main() {

    int a;
    printf("%d\n",&a);

    printf("%d\n",foo);

    return 0;
}

Here is result:

-1075908992 134513684
+4  A: 

You should pass the pointer formatter:

printf("%p\n",foo);
AraK
+20  A: 

Memory addresses should not be interpreted as signed integers in that way. The sign of the number depends on the highest bit set (assuming two's complement representation, which is used by the vast majority of systems currently in use), so a memory address above 0x80000000 on a 32-bit system will be negative, and a memory address below 0x80000000 will be positive. There's no real significance to that.

You should be printing memory addresses using the %p modifier; alternatively, some people use %08x for printing memory addresses (or %016llx on 64-bit systems). This will always print out as an unsigned integer in hexadecimal, which is far more useful than a signed decimal integer.

int a;
printf("%p\n", &a);
Adam Rosenfield
`%08x` is non-portable (and would actually be messed up on an LLP64 platform, for example).
Pavel Minaev
Yes, that's why you should use `%p`, but it's still worth mentioning that a lot of people use `%08x` on 32-bit machines. 99% of the time, if you're printing out a pointer value, you're debugging something, so you know exactly what architecture you're running on.
Adam Rosenfield
+1  A: 

Neither, a pointer doesn't have sign, but when converted to a signed integer it might be positive or negative.

Incidentally, passing a pointer to printf with a format variable designed to print an integer causes undefined behaviour. You should always explicitly cast to the the correct type to get unspecified or implementation defined behaviour (depending on the cast).

Charles Bailey
Right; that could cause real problems on a system where pointers and ints were not the same size (like most 64-bit systems).
David Thornley
+2  A: 

You're printing out in decimal. You probably want to print out the memory location in hexadecimal (using "%p") (most memory addresses are shown in hexadecimal by convention).

McWafflestix
A: 

Use printf("%u",&a);

avd
This is incorrect. %u is for unsigned ints, not for pointers.
ChrisInEdmonton
i like this idea though. it forces address to be positive.
tsubasa
+1  A: 

You could also use printf("%p", &a) as well. %p is the pointer format specifier, to output the value of a pointer in an implementation-defined way. Practically speaking, its pretty much the same as %x, but would handle the case where a pointer is larger than an int.

Jeff Paquette
Good point. You do have to have a recent compiler for this to work though. (Don't laugh, I have to use decades-old compilers depressingly often)
T.E.D.
+5  A: 

To be the most Standard conforming possible, pass "%p" in the format string to printf() and cast the argument to void*.

printf("%p\n", (void*)&a);
printf("%p\n", (void*)foo);

Quote from the Draft Standard (n1401.pdf)

    7.20.6.1 The fprintf function

8   The conversion specifiers and their meanings are:

p       The argument shall be a pointer to void. The value of the pointer
        is converted to a sequence of printing characters, in an
        implementation-defined manner.
pmg
I'd suggest following your own advice an replace `%d` with `%p` in the example code
Christoph
+1 for mentioning the cast to `void *` as default argument promotion doesn't involve any pointer conversion, ie you'll get undefined behaviour on platforms where pointers to different types have different representations
Christoph
A: 

printf isn't some magical interpretation tool. All it is doing if you give it "%d" is showing you what the bit pattern sitting in that variable looks like as an integer.

As to why some pointers are negative and some positive, all that means is that some have the high order bit set and some don't. What addresses are given to objects is really only the business of your operating system (usually with some hardware help). The programming language has no real say in it.

If I were you, I wouldn't be printing out addresses that way. If you really feel the need to look at them, use "%x" instead of "%d". That will print them in hex, which makes it much easier to figure out which bits are on and which ones aren't. Generaly all you are going to care about with addresses is if they are 0 or not, and if they match some other address's value.

T.E.D.
+1  A: 

Pointers are not signed integers, being much more like unsigned integers. However, you're printing them out as if they were signed integers. On a 32-bit system, there are several things that are likely to be 32 bits long: int, unsigned int, float, and pointers. You can't in general tell which these are just by looking at them, but they all mean different things. (As an experiment, you could pass various integers in and print them like floats and vice versa: it's bad practice in general but it can show you that different data types do mean different things.)

Functions that take a variable number of arguments ("variadic" functions) do so in a complicated sort of way. In particular, they don't check argument types. You can pass any arguments you like to printf() and similar functions, but getting them to agree with the format specifier is your problem. This means that the function has no way of getting the type right (as it would if you passed a float to a function like int foo(int)).

Passing the wrong types of arguments leads to undefined behavior, and is particularly likely to lead to problems if you pass arguments of the wrong size. On most 64-bit systems, pointers are 64 bits and ints are 32.

Therefore, you need to use the right thing in the format string. printf("%p", &a); will print out the address of a as a pointer, which is what you want. The standard requires something like printf("%p", (void *)&a);, but as a practical matter that's unnecessary on any computer you are ever likely to encounter.

David Thornley
A: 

Aside from using %p, you could also cast to uintptr_t to make sure to get an unisgned integer.

Use PRIuPTR (or PRIXPTR for hex) form <inttypes.h> to get the correct format specifier:

printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo);
Christoph