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?
CodePudding user response:
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 );
CodePudding user response:
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:
- 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.
- 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.