Reputation: 63
I'm interested in whether an unsigned long long
variable can be treated as an address, and the result seemed it was correct?
int var = 0;
// the variable var's address is 0x7fffffffe4a4 now in my system
unsigned long long ull = 0x7fffffffe4a4;
scanf("%d", ull); // I try to use ull as var's address and assign a value to var
printf("%d\n", var); // It seemingly works!
And I also conducted an experiment as follows.
int var = 0;
// the variable var's address is 0x7fffffffe4a4 now in my system
unsigned long long ull = 0x7fffffffe4a4;
int *ptr = &var;
// First, I want to know whether the memory used by unsigned long long and the one used by a pointer differ
printf("%zu\n", sizeof(ull));
printf("%zu\n", sizeof(ptr));
// The results are both "8" in my system
// Next I try to assign two different values to var by two ways
scanf("%d", ull); // I try to use x as an address to assign var
printf("%d\n", var);
scanf("%d", ptr); // And I also use a normal pointer to assign var
printf("%d\n", var);
// The results were in line with expectations!
Well, it seems an unsigned long long
variable can be used as a pointer successfully (although the compiler warned me that the argument was expected to be int*
rather than unsigned long long
), and I wonder …
What's the difference between a variable and a pointer at the hardware level? How are these two types of objects processed when they are stored and used? Who processes these objects and is it recommended to perform the operations above?
(In the end is it a feature of c?)
Upvotes: 6
Views: 1946
Reputation: 48073
There are two fundamental issues here:
0b111111101000000000000000000000
, or in hexadecimal, 0x3fa00000
. Interpreted as an int
, that's the number 1067450368. Interpreted as a float
, it's 1.25. Same bit pattern, two completely different, totally unrelated numbers. You could take the same bit pattern and try to interpret it as a pointer, but that would be a third, completely unrelated interpretation, and it wouldn't necessarily mean anything, either.So taking an integer value, converting it to a pointer, and then accessing the resulting memory is sort of like chipping golf balls off the top of a tall building: you have no idea where the balls are going to land, and they might hurt someone, and it's therefore a pretty irresponsible practice.
Upvotes: 1
Reputation: 148
They have the same size on certain platforms, and can then be typecast into the other without disregarding any number of bits. There is the size_t
type, which represents the "return" type of sizeof
and the is used to store size used in memory(in bytes) for a variable. size_t
can be only 2 bytes big(sizeof(size_t)
=2
) on some platforms, but long long
(whose sizeof
is the same as the sizeof
of unsigned long long
) is always 8 or higher. It makes sense for pointers to any type to have the same sizeof
. The number of bytes in the memory before the first byte referred to by the pointer is stored in the pointer, so it makes sense that its sizeof
should be same as sizeof
of a pointer to any type. So, I'd recommend using size_t
if you want to store an address in an integral type.
Upvotes: 1
Reputation: 2082
Here is a good analogy: using numbers instead of pointers is not wrong, it's dangerous. Imagine at the reason why you don't use a bicycle on a highway. Is it because you can't ride it? Of course you can, you have wheels, the asphalt is good. You don't do it because it's dangerous, the bicycle is not designed to do it.
For a more formal explanation:
Congratulations, you discovered that addresses are, ultimately, just numbers. The reason why in languages such as C or C++ (they are different!!) pointers are introduced is to avoid confusion and errors, letting the users and the compiler know specifically when they are dealing with an address or a number.
As I said at the beginning, at the end of the day, an address is a number that needs to tell the hardware where to look in the memory. However a pointer is a number that is treated with special care by the compiler:
You have the guarantee that a pointer has enough bits to store the address. Your example works "fine" with 64bits systems, but in a 16bits system a pointer will have the same range as a unsigned short
value, and if you try to assign a unsigned long
you will run into all sorts of problems.
Arithmetic on pointers follow the size of the underlying pointed data type. When you are pointing at a short
at address 0x100
and you want to go to the next byte, you know that you have to look at '0x102'.
short* ps = (short*)0x100;
ps += 1; // ps is now 0x102, because the compiler knows that short is 2 bytes
*ps = 0xAABB;
short s = 0x100;
// I need to advance to the next short.. mmm I have to do this:
s += sizeof(short).
*((short*)s) = 0xAABB; // Also, ugly syntax.
// See how easy it is to make errors when you use plain numbers?
Bottom line: pointers are special numbers with special properties, especially thought to handle memory accesses and address arithmetic.
Upvotes: 6
Reputation: 51904
On many (most) platforms, pointers and (unsigned) integers are stored in very similar formats at the hardware level (on your system, both an int*
pointer and an unsigned long long
are 8 bytes). However, from the point of view of the C language and compiler, they are very different types of variable.
One notable difference in their behaviour concerns arithmetic. For integral types, arithmetic operations like x = x + 1
do exactly what you would naturally expect. However, for pointers, such operations are performed in base units of the size of the pointed-to type.
The following code demonstrates this (on a platform with 8-byte pointers and long long
and a 4-byte int
):
#include <stdio.h>
int main()
{
int myInt = 42;
int* ptr = &myInt;
unsigned long long ull = (unsigned long long)ptr;
printf("%p %016llX\n", (void*)ptr, ull);
++ptr;
++ull;
printf("%p %016llX\n", (void*)ptr, ull);
return 0;
}
The output is:
0000005B8A4FFC10 0000005B8A4FFC10
0000005B8A4FFC14 0000005B8A4FFC11
For the first line (as you have already noted), the two values are identical, and their binary representations will also be the same (on this platform). However, notice that the ++
increment behaves differently on the two types, so that the second line of output shows that the pointer has been incremented by 4
(the size of an int
) but the unsinged integer has been incremented by 1
.
Upvotes: 7