Basically, when you want to perform a type cast, say a float to an integer, it might result in truncation (i.e. the resultant will be a floor value of the initial value). A way of achieving this without losing data is to cast the pointer to that data type, changing the way that pointer is interpreted, and then dereferencing it. This will preserve the exact memory representation of the initial value and will also change its type.
The following code demonstrates pointer casting -
float pi = M_PI;
int i_cast = (int)pi; // type casting
int i_ptr = *(int *)π // pointer casting
A union can also be used for the above problem
NOTE: The above defined scenario of pointer casting might lead to undefined behavior and should be avoided unless one is pretty sure of what is to be achieved. |
After this, we started discussing interesting hacks that can be made use of in C, and here is a cool one which he recalled -
Suppose you have a struct definition in C which contains an array member (let’s say it is an array of ints). While declaring the struct, you don’t know how many elements the array will contain and you also don’t want to declare it with an arbitrary number of elements. How to achieve this ?
The obvious way of achieving this is by using an integer pointer and later allocating memory dynamically. But there is an alternative approach to this problem by taking advantage of the memory representation of a struct.
Suppose the number of elements I want in the array is stored in a variable of type int named count
.
malloc(3)
), we also allocate space for “count” number of integer elements following it. Thus, malloc(3)
will return a pointer to a struct which essentially contains an array of “count” elements.The following C code demonstrates the above described procedure -
#include <stdio.h>
#include <stdlib.h>
typedef struct {
// We don't know how many entries "arr" will contain at this point, so declare
// it to (initially) contain zero elements.
int arr[0];
} test_struct;
int main() {
// `count` contains the number of entries that we desire in the array `arr`.
int count = 4; // NOTE: 4 is chosen arbitrarily
test_struct *str;
// We take advantage of the memory representation of a struct in C. After
// allocating space for `str`, we also allocate space for `count` number of
// ints. This way, the pointer to `test_struct` returned by malloc(3) will now
// contain an array (of size 0), followed by space for `count` number of ints.
// Thus, `arr` will behave exactly as a `count` sized array.
str = (test_struct*) malloc(sizeof(test_struct) + count * sizeof(int));
// A simple test for validity: populate "arr" and print its contents.
for (int i = 0; i < count; i++) {
str->arr[i] = i;
}
for (int i = 0; i < count; i++) {
printf("%d\n", str->arr[i]);
}
return 0;
}
To summarize, the title of the post can be answered in two words - A LOT!
Thanks for reading!
Leave a Comment