Yesterday I was in class, and at some point the instructor was talking about C code. He said:
What is the purpose of making a pointer cast in C? The only
Casting from void* to a type i need in my program (e.g. int*, char*, struct x*) makes sense to me. But casting across other types i.e. int* to char* etc. can become problematic (due to the offsets being different for ints, chars etc). So be careful if doing so.
But ... to specifically answer your question, consider the following:
int_pointer = malloc(2 * sizeof(int)); // 2 * 4 bytes on my system.
*int_pointer = 44;
*(int_pointer + 1 )= 55;
printf("Value at int_pointer = %d\n", *int_pointer); // 44
printf("Value at int_pointer + 1 = %d\n", *(int_pointer + 1)); // 55
(The offsets above will be in 4 byte increments.)
//char_pointer = int_pointer; // Gives a warning ...
char_pointer = (char*)int_pointer; // No warning.
printf("Value at char_pointer = %d\n", *char_pointer); // 0
printf("Value at char_pointer = %d\n", *(char_pointer+1)); // 0
printf("Value at char_pointer = %d\n", *(char_pointer+2)); // 0
printf("Value at char_pointer = %d\n", *(char_pointer+3)); // 44 <==
Four bytes were allocated to the int value of 44. Binary representation of 44 is 00101100 ... the remaining 3 bytes are all 0s. So when accessing using char* pointer, we increment 1 byte at a time and get the above values.
Casting for pointers is essential to say the compiler how to perform pointer arithmetic.
For example if x is a character pointer pointing to memory 2001, x++ should go to 2002, but if x is an integer pointer x++ should be 2003
so if type casting is not done for pointers compiler won't be able to perform pointer arithematic properly.
What your Prof said sounds right.
...(for example, adding an int pointer will result in a different offset than adding a char pointer)
This is true because assuming int
is 4 bytes and char
is 1 byte, adding a 2
to an int pointer will result in moving the pointer by 8 bytes, whereas adding a 2
to a char pointer will only move the pointer to the next byte 2 positions away.
Apart from that, there is no difference: all pointers are represented the same way in memory, regardless if the pointer is pointing to an int value, a char value, a short value, or whatever.
This is true, the machine makes no distinction between char vs int pointers, these are the compiler's issue to deal with. Also as your prof mentioned:
So, casting a pointer will not modify anything in the memory, it will just help the programmer with operations more related with the pointer-type he is dealing with.
This is again true. Casting does not modify memory, it just changes how a part of memory is interpreted.
Not casting pointers in C can cause problems?
There is no implicit conversion between pointer types in C (as there are for example between arithmetic types) - with the exception with void *
type. It means C requires you to cast if you want to convert a pointer to another pointer type (except for void *
). If you fail to do so an implementation is required to issue a diagnostic message and is allowed to fail the translation.
Some compilers are nice enough (or pervert enough) to not require the cast. They usually behave as if you explicitly put the cast.
char *p = NULL;
int *q = NULL;
p = q; // not valid in C
In summary you should always put the cast when converting pointers to pointers for portability reasons.
EDIT:
Outside portability, an example where not casting can cause you real problems is for example with variadic functions. Let's assume an implementation where the size of char *
is larger than the size of int *
. Let's say the function expects the type of one argument to be char *
. If you want to pass an argument of int *
, you then have to cast it to char *
. If you don't cast it, when the function will access the char *
object some bits of the object will have an indeterminate value and the bevahior will be undefined.
A somewhat close example is with printf
, if a user fails to cast to void *
the argument for the p
conversion specifier, C says it invokes undefined behavior.
Casting a pointer doesn't change the pointer value, it only tells the compiler what to do with the pointer. The pointer itself is just a number, and it doesn't have a type. It's the variable where the pointer is stored that has the type.
There is no difference between your two ways of assigning the pointer (if the compiler lets you do the assigment). Whatever the type of the source pointer variable, the pointer will be used according to the type of the destination variable after the assignment.
You simply can't store an int pointer in a char pointer variable. Once the value is stored in the variable, it has no notion of having been a pointer to an int.
Casting pointers matters when you use the value directly, for example:
int* int_pointer;
int_pointer = malloc(sizeof(int));
*int_pointer = 4;
char c;
c = *(char*)int_pointer;
Casting the pointer means that dereferencing it reads a char from the location, not an int.
What your instructor said about all pointer types sharing the same representation is generally true for real-life implementations of C language.
However, it is not true from the point of view of abstract C language itself. C language guarantees that
char *
pointers are represented in the same way as void *
pointers.T
(const
, volatile
, restrict
) are represented in the same way as pointers to unqualified T
.That is all. No other guarantees exist. Which means that as far as the language itself is concerned, int *
pointer has different representation from double *
pointer. And pointer to struct S
is represented differently from pointer to union U
.
However, your example with char_pointer
and int_pointer
, as presented, is not exactly illustrative. The char_pointer = int_pointer;
assignment is simply invalid (as in "does not compile"). Language does not support implicit conversions between incompatible pointer types. Such conversions always require an explicit cast operator.