Whats the difference between integer and the address returned by & ?
Therefore, why should I type-cast integer to an integer pointer when assigning it to an integer pointer?
Integer and pointer to integer are different types.
Integer variable holds integer value.
Pointer variable holds address value.
Given your example:
int value = 5;
int address = &value;
value is variable of type int.
&value returns address of type int*
address = &value tries to assign int* to int.
While integers can be converted to pointers and back, it doesn't mean that addresses are necessarily integer values.
Just like you can assign double to int, you can assign int * to int. But it's not necessarily what you want, and that's why compiler warns about it.
In fact, unless you are working very close to hardware (writing driver for example), it's very unlikely you need to do conversions between integers and pointers.
Correct way to do this, without needing any casts:
int * pointer = &value;
Whats the difference between integer and the address returned by & ?
I think this question has already been answered in the comments. The difference is the type of those variables. Basically int = Integer type and *int = Pointer type.
Furthermore: Conversion from pointer to int can result in undefined behavior.
Therefore, why should I type-cast integer to an integer pointer when
assigning it to an integer pointer?
Because the standard says:
C99 Section 6.5.4 and 6.5.16.1:
Conversions that involve pointers, other than where permitted by the
constraints of 6.5.16.1, shall be specified by means of an explicit
cast.
And C++ Section 5.4:
Any type conversion not mentioned below and not explicitly defined by
the user (12.3) is ill-formed.
Related
In my code I have two char pointer, one to a string and the other as an error indicator for strtoumax() and strtod(). I am currently using the type size_t (aka unsigned long) to calculate the difference between them. Is there any type designed to specifically match pointer type size on every machine? Or do I have to check it myself with macros?
For pointer difference use ptrdiff_t. If you're just trying to store a pointer as an integer, use uintptr_t (or intptr_t).
In my code I have two char pointer, one to a string and the other as
an error indicator for strtoumax() and strtod(). I am currently using
the type size_t (aka unsigned long) to calculate the difference
between them.
Don't do that. If you want a pointer difference then compute a pointer difference:
#include <stdint.h>
// ...
ptrdiff_t difference = p2 - p1;
And note ptrdiff_t, which is the type of the result of a pointer difference.
If you want a difference in bytes instead of in units the size of the pointed-to type (including if the pointed-to type is incomplete, such as void) then first convert to pointers to char:
ptrdiff_t difference_in_bytes = (char *) p2 - (char *) p1;
(char is the smallest addressible unit of storage, but technically, it might be larger than 8 bits on some C implementations. CHAR_BIT will help you figure that out if you're concerned about such cases.)
Do not compute a pointer difference by converting to integer and performing integer arithmetic, because although the behavior of that is defined (+/- signed integer overflow), the meaning of the result is not.
Is there any type designed to specifically match pointer
type size on every machine? Or do I have to check it myself with
macros?
Yes. In stdint.h there are definitions of uintptr_t and intptr_t, which can support round-trip pointer to integer to pointer conversions without data loss. But C does not define the meaning of the value resulting from converting a pointer to an integer, so these are best used as opaque types.
To store pointers as integers you can use intptr_t and uintptr_t declared in the header <stdint.h>.
From the C Standard (7.20.1.4 Integer types capable of holding object pointers)
1 The following type designates a signed integer type with the
property that any valid pointer to void can be converted to this type,
then converted back to pointer to void, and the result will compare
equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the
property that any valid pointer to void can be converted to this type,
then converted back to pointer to void, and the result will compare
equal to the original pointer:
uintptr_t
These types are optional.
To store difference between two pointers you can use ptrdiff_t declared in the header <stddef.h>.
Pay attention to that you may calculate difference between two pointers if they both point to elements of the same array or one past the last element. Otherwise you will get undefined behavior.
How is this allowed in C?
int p= (int) malloc (sizeof(int));
I only get a warning when I compile in gcc.
warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
A void pointer cannot be casted to a primitive type right?
*((int*)(x))//is allowed - assume x is of type void*
But how is direct cast to primitive also allowed?
This is not forbidden, but implementation defined behaviour. Quoting C11, chapter ยง6.3.2.3
Any pointer type may be converted to an integer type. Except as previously specified, the
result is implementation-defined. If the result cannot be represented in the integer type,
the behavior is undefined. The result need not be in the range of values of any integer
type.
That is why compiler emits the warning.
That said, quoting chapter 7.20.1.4, Integer types capable of holding object pointers, we have intptr_t and uintptr_t.
The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
uintptr_t
Having said that, just for sake of completeness's sake, let me add that, there is fair amount of reasons on why not to cast the return value of malloc() and family in C..
Take a look at the following program. What I don't understand is why do I have to cast the address of the variable x to char* when it actually would be absolutely useless if you think about it for a second. All I really need is only the address of the variable and all the necessary type information is already in place provided by the declaration statement char* ptr.
#include <stdio.h>
int main(void) {
int x = 0x01020309;
char* ptr = &x; /* The GCC compiler is going to complain here. It will
say the following: "warning: initialization from
incompatible pointer type [enabled by default]". I
need to use the cast operator (char*) to make the
compiler happy. But why? */
/* char* ptr = (char*) &x; */ /* this will make the compiler happy */
printf("%d\n", *ptr); /* Will print 9 on a little-endian machine */
return 0;
}
The C Standard, 6.2.5 Types, paragraph 28 states:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall have
the same representation and alignment requirements as each other.
All pointers to union types shall have the same
representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Since different types of pointers can have differing implementations or constraints, you can't assume it's safe to convert from one type to another.
For example:
char a;
int *p = &a
If the implementation has an alignment restriction on int, but not on char, that would result in a program that could fail to run.
This is because pointers of different types point to blocks of memory of different sizes even if they point to the same location.
&x is of type int* which tells the compiler the number of bytes (depending on sizeof(int)) to read when getting data.
Printing *(&x) will return the original value you entered for x
Now if you just do char* ptr = &x; the compiler assigns the address in &x to your new pointer (it can as they are both pointers) but it warns you that you are changing the size of the block of memory being addressed as a char is only 1 byte. If you cast it you are telling the compiler that this is what you intend.
Printing *(ptr) will return only the first byte of the value of x.
You are correct that it makes no practical difference. The warning is there to inform you that there might be something fishy with that assignment.
C has fairly strong type-checking, so most compilers will issue a warning when the types are not compatible.
You can get rid of the warning by adding an explicit cast (char*), which is you saying:
I know what I'm doing, I want to assign this value to my char* pointer even if the types don't match.
Its just simple as you assign integer type to character. similarly you are trying to assign integer type pointer to character type pointer.
Now why is so because this is how c works, if you increment a character pointer it will give you one byte next address and incrementing integer pointer will give you 2 byte next address.
According to your code, x is of type int. So the pointer that points to x should be of type int *. Compiler gives such error because you use a pointer which is not int *.
So make your pointer either int *, or void * then you don't need cast.
Afaik uintptr_t and intptr_t can be used to hold any pointer to void. Hence these types can be used to store pointers to data.
In C99 or later, are there similar signed and unsigned integer types capable of holding pointers to functions?
No, there are no such types.
Function pointers may only be reliably cast to other function pointer types (and then, only dereferenced while pointing to the correct function type).
The conversion of function pointers to integers in C is covered by 6.3.2.3/6:
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
Note that even if the integer type is large enough, casting to integer and back to function pointer is not guaranteed to retrieve the original function pointer.
In C++, the text is in [expr.reinterpret.cast] points 4 and 6. The behaviour is similar, but it explicitly guarantees that if an integer of sufficient size exists, then converting function pointer to integer and back again does retrieve the original function pointer.
I am writing my own functions for malloc and free in C for an assignment. I need to take advantage of the C sbrk() wrapper function. From what I understand sbrk() increments the program's data space by the number of bytes passed as an argument and points to the location of the program break.
If I have the following code snippet:
#define BLOCK_SIZE 20
int x;
x = (int)sbrk(BLOCK_SIZE + 4);
I get the compiler error warning: cast from pointer to integer of different size. Why is this and is there anyway I can cast the address pointed to by sbrk() to an int?
I get the compiler error warning: cast from pointer to integer of different size.
Why is this
Because pointer and int may have different length, for example, on 64-bit system, sizeof(void *) (i.e. length of pointer) usually is 8, but sizeof(int) usually is 4. In this case, if you cast a pointer to an int and cast it back, you will get a invalid pointer instead of the original pointer.
and is there anyway I can cast the address pointed to by sbrk() to an int?
If you really need to cast a pointer to an integer, you should cast it to an intptr_t or uintptr_t, from <stdint.h>.
From <stdint.h>(P):
Integer types capable of holding object pointers
The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to a pointer to void, and the result will compare equal to the original pointer: intptr_t
The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to a pointer to void, and the result will compare equal to the original pointer: uintptr_t
On XSI-conformant systems, the intptr_t and uintptr_t types are required; otherwise, they are optional.