简体   繁体   中英

Unusually Large values and negative values of addresses of a variable

So I was learning and practicing the concept of Pointers and addresses of variables in C language. But there is one thing that is making me curious. The code that I ran is-

    #include <stdio.h>

    int main()
    {
       int *p, n;
       p = &n;
       int *c = NULL;

       printf("Address of variable = %p\n", p);
       printf("Address of variable = %lu\n", p);
       printf("Address of c variable = %lu\n", c);
       return 0;
    }

I am sure that this code is correct to print addresses and the output I got was-

    pointer.c: In function ‘main’:
    pointer.c:10:37: warning: format ‘%lu’ expects argument of type ‘long unsigned 
    int’, but argument 2 has type ‘int *’ [-Wformat=]
        10 |     printf("Address of variable = %lu\n", p);
           |                                   ~~^     ~
           |                                     |     |
           |                                     |     int *
           |                                     long unsigned int
           |                                   %ls
    pointer.c:11:39: warning: format ‘%lu’ expects argument of type ‘long unsigned 
    int’, but argument 2 has type ‘int *’ [-Wformat=]
        11 |     printf("Address of c variable = %lu\n", c);
           |                                     ~~^     ~
           |                                       |     |
           |                                       |     int *
           |                                       long unsigned int
           |                                     %ls
   Address of variable = 0x7fffc5a57474
   Address of variable = 140736509342836
   Address of c variable = 0

So, I was wondering that as to what do these compiler warnings mean, and should I be concerned about these warnings?

Also, when I used %d instead of %p or %lu , I got the values of addresses as a "negative" value, so can negative addresses exist in the memory?

Also, the address values in the output are unusually large. They are even larger than the size of my 16 GB RAM, how is that possible that my variable is stored in a location which doesn't exist?

You have to be careful if you're thinking about pointers as numbers. Internally, they are usually addresses, and they are usually numeric, but they are unsigned numeric. So, no, you typically won't have "negative addresses".

You might not have learned how computers represent negative numbers. Here's a quick demonstration of the common " two's complement " representation, using only three bits. The point is that the same bit pattern can have two different interpretations, depending on whether you care about negative values or not:

bit pattern signed int unsigned int
000 0 0
001 1 1
010 2 2
011 3 3
100 -4 4
101 -3 5
110 -2 6
111 -1 7

So, as you can see, if you have a large, unsigned number, but you interpret it as if it's signed (like, by printing it with %d , you get a negative number, instead.

Two other things to remember are:

  1. Pointers aren't necessarily ints. They might be — and on the currently-popular x86_64 architecture, they are — larger than ints. So trying to print them using %d is doubly wrong, and might give you a completely misleading answer.
  2. Your program often uses memory in different parts of the "address space". For example, it's common for your program's instructions, and its global variables, to be allocated in the low part of memory, starting at or near address 0. But it's common for the "stack", where local variables are typically stored, to start somewhere towards the top of the address space, and grow down. So it's common for the address of a local variable to be a very large number, seemingly bigger than the amount of memory you have in your machine. But what's actually going on is that the seemingly huge amount of memory in between isn't allocated at all, isn't "mapped in" to your address space, and so doesn't count against the amount of physical memory you have in your computer.

Your code is not correct.

The conversion specifier lu expects its corresponding argument to have type unsigned long and d expects its corresponding argument to have type int ; p and c have type int * , hence the warnings. And yes, these warnings matter - at the very least you're going to get garbled output, as you've discovered.

Pointer types are not integer types; they don't have to have the same size or representation as integer types (on x86_64, int is 32 bits wide but pointer types are 64 bits wide). The only conversion specifier that is defined for pointer types is p , and it expects its corresponding argument to have type void * .

Your code should be written more like

printf( "p = %p\n", (void *) p );
printf( "c = %p\n", (void *) c );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM