Can unsigned int replace Pointers in C - c

As range of "unsigned int" is equal to range of " int *" or any pointer since both take 4Bytes in 64bit platform. Can pointer in C can be replaced by unsigned int ??

There is no such guarantee for unsigned int. A special type uintptr_t was introduced in C99 to hold a pointer, regardless of the platform. You need to include <stdint.h> header to use this type.

Absolutely not. Pointers may be eight bytes, not four, on a 64-bit platform! You can sometimes get away with casting between long long and a 64-bit pointer, but even that is questionable.

You cant even be sure that int is 4 Bytes in 64Bit arch! as the type limits are absolutly implementation and enviroment defined. The standard only gives a limitation of which value has to have at least which range. Thats all. int could even be 8 Bytes on 64 Bit it could be 10 Bytes, or it could be 13 Bytes or it could be What ever the enviroment wants its size to have. So ofcourse you can replace it. But it could end in invalid alignments or cause data loss.
As each assignement of types of different size can have.
But at least you can assign a pointer value to an int value. But also this is the only conversion from value type to pointer type which is valid by ISO/IEC9899.

Short answer: no.
Slightly longer answer: there's no guarantee that unsigned int will be able to hold a valid pointer value for a given platform (several people have already pointed out that 64-bit platforms will likely have address values that fall outside of the range of unsigned int). This is further complicated by the fact that pointers to different types may have different sizes and representations.
Pointers don't just encode an address value; they also encode a type. This matters for pointer arithmetic and array subscripting. For example, assume the declarations:
char *cp = 0x4000;
int *ip = 0x4000;
float (*dap)[10] = 0x4000;
All three pointers (cp, ip, dap) start out with the same value: 0x4000. However, adding 1 to each pointer will give different results. Assuming 32-bit int and float types, we'd get:
cp + 1 == 0x4001
ip + 1 == 0x4004;
dap + 1 == 0x4028;
Adding 1 to cp gives us the address of the next char object (0x4001), adding 1 to ip gives us the address of the next int object (0x4004), and adding 1 to dap gives us the address of the next 10-element array of float object (0x4028). This allows us to use the [] operator on each pointer: we can write cp[i] and ip[i] and get the result we expect (the i'th element following the pointer). If you typed all those pointers as unsigned int, however, you wouldn't be able to use the subscript operator, and adding 1 to them would only give you the next byte address, not necessarily the address of the next object.

Related

Can I treat an 'unsigned long long' variable as an address to assign another variable?

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?)
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.
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.
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.
There are two fundamental issues here:
Interpretation matters. In almost any programming language, the values we work with are not just raw bit patterns, they are bit patterns interpreted as a particular type. For example, consider the binary number 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.
Just because you have a pointer value, pointing at (or containing) a certain memory address, doesn't necessarily mean you can actually access that memory. It might be in use by some other variable in your program. It might be in use by the actual code of your program. It might be in use by some other program. Or it might not exist at all — it might refer to a memory address that's higher than the total amount of memory in your computer.
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.

C programming pointer, bytes and memory allocation have 8 question

I am trying to get the bytes and pointers and how they are stored can any one explain or answer some of my questions. Thank you
int num = 513; <-- allocating a 4 bit memory by initializing
//[01][02][00][00] <-- (numbers are sorted and shown as litle endian)
char * ptr = &num; //char is (one byte)
↓
//[01][02][00][00]
// pointer always start from the [0] (as in this array byte length)
// in the allocated address in the memory ptr[0] is in this case = [01]
// (printed as %x02 "printf("the byte %02x\n",ptr[0]);" - if it's only
//single number 1 a zero will be added on the length so it prints out as 01)
int * ptr = &num; //now creating a pointer with the type of int (four bytes)
↓ ↓ ↓ ↓
//[01][02][00][00]
how can i access the first byte of this int pointer? [question01]
is there a way to see the bites inside the of the first byte([01])? [question02]
where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
where does this int pointer stores it's type length (4bytes)? [question05]
what happens if i declare a type with longer byte memory allocation such as long long * ptr = &num; [01][02][00][00][00][00][00][00]
since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
Note: char * ptr = &num; should really be unsigned char * ptr = (unsigned char *)&num; to avoid compiler warnings and to ensure that the bytes are treated as unsigned values.
how can i access the first byte of this int pointer? [question01]
If you really want to access the first byte of a pointer, you can use:
unsigned char *ptr2 = (unsigned char *)&ptr;
then ptr2[0] is the first byte of the pointer ptr.
is there a way to see the bites inside the of the first byte([01])? [question02]
I assume you mean the bits inside the first byte. Bits are not directly addressable, so you need an expression (usually with bit-wise operators) to get the value each bit. For example, (ptr[m] >> n) & 1 will be the value of the nth bit of the mth byte of an object (where ptr is an unsigned char * pointing to the start of the object).
where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
Addresses are stored in pointer variables in the same way as numbers are stored in variables of numeric type. At the CPU instruction level, there is no difference between a stored pointer value and a stored integer value, other than the width.
The most typical sizes of pointer types are 8 bytes or 4 bytes, depending on the target architecture of the compiler.
(There is no question04.)
where does this int pointer stores it's type length (4bytes)? [question05]
It doesn't store the length of the type, but the compiler knows that a TYPE * points to an object that is sizeof(TYPE) bytes long.
what happens if i declare a type with longer byte memory allocation such as long long * ptr = # [01][02][00][00][00][00][00][00] since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
If the pointer is not correctly aligned for the referenced type (long long) then the behavior is undefined. Otherwise it can be converted back to the original pointer type int *. In any case, accessing *ptr will result in undefined behavior (unless long long is the same width as int, which is not typical).
binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
It is called a bit. There is also a type called _Bool. Expressions of type _Bool always have the value 0 or 1.
one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
Who cares what some random web-site displays?
What C calls a "byte" is any type where sizeof(type) is 1, including char, signed char and unsigned char. It is at least 8 bits wide, but is wider than 8 bits on some exotic systems.
A pointer of character type (char *, signed char * or unsigned char *) can be used to access the individual bytes within any object, but that might not be true for pointers of other size 1 types, and is certainly not true for pointer to _Bool (_Bool *)!
• how can i access the first byte of this int pointer? [question01]
Generally, it is preferable to use unsigned char rather than char to access arbitrary bytes, so let’s do that.
After unsigned char *ptr = &num;, ptr is a pointer to unsigned char, and you could access the first byte of the int with *ptr or ptr[0], as in printf("The first byte, in hexadecimal, is 0x%02hhx.\n", *ptr);.
If instead you have int *ptr = &num;, there is no direct way to access the first byte. ptr here is a pointer to an int, and, to access an individual byte, you need a pointer to an unsigned char or other single-byte type. You could convert ptr to a pointer to unsigned char, as with (unsigned char *) ptr, and then you can access the individual byte with * (unsigned char *) ptr.
• is there a way to see the bites inside the of the first byte([01])? [question02]
The C standard does not provide a way to display the individual bits of a byte. Commonly programmers print the values in hexadecimal, as above, and read the bits from the hexadecimal digits. You can also write your own routine to write binary output from a byte.
• where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
A pointer is a variable like your other int and char variables. It has space of its own in memory where its value is stored. (This model of variables having memory is used to specify the behavior of C programs. When a program is optimized by a compiler, it may change this.)
In current systems, pointers are commonly 32 or 64 bits (four or eight 8-bit bytes), depending on the target architecture. You can find out which with printf("The size of a 'char *' is %zu bytes.\n", sizeof (char *));. (The C standard allows pointers of different types to be different sizes, but that is rare in modern C implementations.)
• where does this int pointer stores it's type length (4bytes)? [question05]
The compiler knows the sizes of pointers. The pointer itself does not store the length of the thing it is pointing to. The compiler simply generates appropriate code when you use the pointer. If you use *ptr to get the value that a pointer points to, the compiler will generate a load-byte instruction if the type of ptr is char *, and it will generate a load-four-byte instruction of the type of ptr is int * (and int is four bytes in your C implementation).
• what happens if i declare a type with longer byte memory allocation such as long long * ptr = # [01][02][00][00][00][00][00][00] since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
When long long is an eight-byte integer, and you have a long long *ptr that is pointing to a four-byte integer, the C standard does not define the behavior when you attempt to use *ptr.
In general-purpose multi-user operating systems, the memory after the int cannot be allocated by another program (unless this program and the other program have both arranged to share memory). Each process is given its own virtual address space, and their memory is kept separate.
Using this long long *ptr in your program may access memory beyond that of the int. This can cause various types of bugs in your program, including corrupting data and alignment errors.
• binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
One binary digit is a “bit”. Multiple binary digits are “bits”.
The smallest group of bits that a particular computer operates on as a unit is a “byte”. The size of a byte can vary; early computers had bytes of different sizes. Modern computers almost all use eight-bit bytes.
If your program includes the header <limits.h>, it defines a macro named CHAR_BIT that provides the number of bits in a byte. It is eight in almost all modern C implementations.
• one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
The web site is not merely converting to one byte.
It seems to show at least 16 bits, choosing the least of 16, 32, or 64 bits that the value fits in as a signed integer type.

Why can't you store an extremely large single value in a dynamically allocated block of memory?

Why can't I store a large integer in this allocated block of memory?
int *dyn = malloc(16);
*dyn = 9999999999;
printf("%lli\n", *dyn);
free(dyn);
At compile-time, GCC warns me that an integer overflow will occur. And sure enough, when printed out, it has overflowed.
Why can't I use the entire block of memory to store a single value?
*dyn = 9999999999; does not instruct the computer to use all the memory that was allocated for dyn to store the value 9999999999.
In C, dyn has a type. The type is “pointer to int”. Then *dyn has type int, which has a specific, fixed number of bits. It does not have a type meaning “all the memory that was allocated for dyn”.
Since *dyn is an int, *dyn = 9999999999; tells the computer to put 9999999999 into an int. Since 9999999999 is too big for an int in your C implementation, an overflow occurs.
We can program computers and design programming languages to manage integers of arbitrary sizes. Some languages, such as Python, do this. However that requires extra software, particularly software that has to do some variable amount of work when the program is running in order to handle whatever sizes of numbers come along. C is designed to be an elementary language. It works with objects of specific sizes and generally translates C code to fixed amounts of work in processor instructions. These provide building blocks for programmers to build bigger software. So, in C, int objects have fixed sizes. Allocating 16 bytes of memory provides space for several int objects, but it does not provide a big integer object.
The size of int is usually 4 bytes (32 bits). And, it can take 2^32 distinct states from -2147483648 to 2147483647.
So when you try to store this *dyn = 9999999999; , integer overflow occurs.
It is not pointing to the memory location, it is pointing to the value of that variable.
Why can't I use the entire block of memory to store a single value?
Because the size of int is almost certainly not 16 bytes, and when you de-reference a int pointer in the *dyn = 9999999999; expression, that access is limited to the size of int, which is likely 2^31 - 1.
Please note that the integer constant 9999999999 has a type too, which is dynamically determined by the compiler depending on the number's size. In this case, very likely long long. So the actual bug here is your attempt to do int x = 9999999999; which isn't the slightest related to malloc or pointers. It's a simple overflow.
To use numbers larger than 2.14 billion, you must use a 64 bit type instead. Use int64_t/uint64_t from stdint.h.
You cannot allocate 16 bytes, memcpy som value in there and then access the data through pointers to some arbitrary integer type. This is because of the somewhat dysfunctional C type system. Simplified explanation: the chunk of data returned from malloc has no type internally, until you store something there. Then it gets the type you used when storing, and all subsequent access have to use that same type too, everything else invokes undefined behavior according to "the strict aliasing rule".
dyn is an integer pointer (actually, pointing to a reserved memory of int array of 16 bytes). *dyn is an integer (first element from this int array). As similar to arrays:
int dyn[4];
dyn[0]=9999999999;
Assigning 9999999999 to int leads to a variable overflow, since int allows on modern platforms only [−2 147 483 648, +2 147 483 647] range (and at least [−32767, +32767]).
9999999999 or better illustrated as 9,999,999,999 is not in the range of an int, to which dyn is pointing to, don´t matter how much memory malloc has allocated:
int *dyn = malloc(16); // `dyn` points to an `int` object, don´t matter
// if malloc allocates 16 bytes.
*dyn = 9999999999; // Attempt to assign an out-of-range value to an `int` object.
An object of type int shall be allocated by 4 Bytes in memory by the most modern systems.
4 Bytes can hold a maximum of 2^(8*4) = 2^32 = 4,294,967,296 values.
Now you have the type of int which is equivalent to the type of signed int.
signed int can store positive and negative numbers, but since it can store positive and negative numbers it has quite a different range.
signed int has the range of -2,147,483,648 to 2,147,483,647 and so is the range of int.
So you can not hold 9,999,999,999 in an int object because the maximum value an int object can store is the value of 2,147,483,647.
If you want to store the value of 9,999,999,999 or 9999999999 in an object, use f.e. long long int, but not long int since long int can hold the same range of an int and an unsigned int:
long long int *dyn = malloc(16); // `dyn` points to an `long long int` object.
*dyn = 9999999999; // Fine, because 9999999999 is in the range of an `long long int` object.

How to get the Physical address of a C pointer as a value?

in my system,
sizeof(void*) = 8 bytes
size of all pointer types is 8 bytes.
I have this struct
struct element{void* value};
so this struct is jus a pointer value of 8 bytes.
since all type of pointers have 8 bytes, I should be able to just assign the physical address of any type of variable to this void* value
also,
sizeof(double) = 8 bytes;
question is how do I obtain the physical address of any pointer as a double value and then assign this value to any other 8 byte pointer.
so say,
int i;
int *p = &i;
struct element e;
double phy_address = ?? // the 8 byte value of p (when we print it as %d)
/*now copy this 8 byte phy_address to 8 byte void pointer e.value. */
Is it possible to typecast it as int* or any other pointer type? its jus an address...
On most systems there is an integer type that is the same size as a void *. Usually this type is int or long int or long long int. Most compilers will provide the type, intptr_t (and its unsigned cousin uintptr_t), that is a typedef of one of these types. I think people prefer to use uintptr_t because negative address values usually don't make sense. Anyway you should probably use this type instead of double.
Remember that uintptr_t is just one of the regular integer types, so once you get the pointer value into a variable of this type, you can do any integer arithmetic you like. As for how to get the pointer value into a uintptr_t, see this question/answer, Converting a non-`void` pointer to `uintptr_t` and vice-versa.
I use= these values can be used as unique identifier in a table.
OK. This information is necessary because there is no possibility to convert a pointer into a floating-point number with any meaningful value; the floating-point number will have a meaningless value in any way.
There are two possibilities to convert a pointer to a (meaningless) floating-point value but in both cases you are not guaranteed that two floating-point numbers are unique for two different pointers!
Possibility 1:
Convert the pointer to an integer and the integer to floating-point:
phy_address = (double)(uintptr_t)p;
However as Weather Vane already mentioned in his comment double values have a limited precision.
The integer values (addresses) 1234567890123456780 and 1234567890123456790 would both be rounded to 1234567890123456768.0.
Possibility 2:
Because both double and pointers are 64 bits wide you could generate a floating-point number that has the same bits as the pointer:
union {
void *p;
double d;
} u;
...
u.p = p;
phy_address = u.d;
However there are numbers (for example the 0) which have two different representations in the double data type. This means that there are two different combinations of bits (and therefore two different addresses) that will generate the same number.
For this reason there cannot be any method to convert a 64-bit value into a double value resulting in an unique double value: The data type double has less than 2^64 different values!
And it is even worse:
There are special values - so called "NaN" values. And there are a lot of them!
I just did the following test:
// Write a "NaN" value to a
...
b = a;
if(a == b) puts("equal");
if(a != b) puts("not equal");
// Check if a and b still contain the same value
...
... and I get the result "not equal" although the check at the end says that a and b still contain the same value!
Depending on your environment some NaN values (so-called "signalling NaN" values) might even cause your program to crash!
Conclusion
Personally I would never use floating-point data types as "unique identifier".
In your case I would directly use void * as "unique identifier". If this is not possible I would use some 64-bit integer data type as "Stuart" already suggested in his answer.

Casting from a pointer to an integer. What is actually happening?

Casting from a pointer to an integer. What exactly happens? Here are some of the ways i think it could happen:
the C code automatically get the value in the address pointed at by the pointer and inserts it in to the integer.
integer take the address in the pointer and stores the address in the 4 bytes.
Reason i am asking is because changing from 32 bit to 64 bit a pointer can not be cast to a integer any more. That is because the size of memory a pointer takes is 64 bit which is 8 bytes.
A pointer could be pointing to an integer or a long since we do not know the value size the pointer is pointing to.
Is it the pointer address can not be stored in the integer or the value it contains can not be stored in the integer?
Say this simple code. This will not work on 64bit. Even though the pointer is to be treated as an integer it can not be cast. This leads me to believe that it is not taking the value but the address of the pointer and inserting it in to the integer.
In 32 bit the integer takes the pointer address and knows that it has
to take 4 bytes from that pointer address to get the full value.
Is that statement correct?
int main(void){
int number = 3;
int * pnumber = &number;
int castNumber = (int)pnumber;
}
I had a look at this question but still did not make sense what is actually happening under the hood.
http://c-faq.com/ptrs/int2ptr.html
Casting actually says to the conpiler ''take a look at the value here and treat it as another type''. In case of pointer, the address which is kept by pointer becomes now an integer. And yes, in 64 bit mode you cannot store sn address as integer but as long int.
Example:
int k=3;
int *pInt = &k;
long int castPtr = (long int)pInt;
int *another_pInt = (int*)castPtr; // *another_pInt is now 3
EDIT:
Prefer unsigned long over long int. You probably should not care about the sign of the value since it ia an address.
This leads me to believe that it is not taking the value but the address of the pointer and inserting it in to the integer.
Offcourse it is not taking the value that the pointer is pointing at.
To get the value that the pointer is pointing at, you need to do *pnumber(dereference). Using only pnumber you will get the address to which the pointer is pointing to.
When you store a pointer address in an integer data type, the result would depend on cases.
1) If the integer data type and the length of the address are different, then the extra bytes of the address would be lost when storing it in a variable of integer data type.
2) In cases when the size is same, you can store the address in an integer data type. But, i cannot think of a situation when you would need to.
Another point is, if the size of the integer data type and the address is same, you can convert to int and back to the address safely. Read this, See this.

Resources