Generic pointer in C
What in C is a generic pointer?
In the language C, a "void pointer" (or void*) is a specific type of pointer. Without defining the precise data type at the time of declaration, the void* type is used to represent a pointer that can point to objects of any data type. When you don't know the precise data type that a pointer will point to, it gives you more handling options.
The use of the void* pointer, which is sometimes referred to as a "generic pointer," may be the cause of the misunderstanding. Although it is not a genuine "generic" type like in other programming languages like C++ templates or Java generics, the void* pointer is a specific sort of pointer that can store the address of any data type.
Syntax of generic pointer
However, using void pointers (void*) and explicit type casting, you can emulate a generic-like behaviour in C. Working with void pointers requires the following syntax:
Introducing a global pointer:
void* genericPointer;
Giving the generic pointer any data type's address:
int intValue = 42;
float floatValue = 3.14;
genericPointer = &intValue; // The generic pointer now holds the memory address of intValue
genericPointer = &floatValue; // Now the generic pointer holds the memory address of floatValue
Explicit type casting is needed in order to dereference the generic pointer:
int dereferencedInt = *(int*)genericPointer;
float dereferencedFloat = *(float*)genericPointer;
Please be aware that whenever you want to access the real data that void pointers point to, you must explicitly type cast. If handled improperly, this lack of type safety may cause problems.
In conclusion, while C does not provide real generic pointers, you can get a generic-like behaviour by using void pointers and explicit type casting, however it may necessitate extra care to ensure proper type handling. Use C++ templates or other programming languages with native support for generics for more reliable and type-safe generic programming.
Size of generic pointer
The size of a generic pointer in C, which is a void* pointer, depends on the implementation. As it is intended to carry the address of any data type, a void* pointer will normally be the same size as a standard data pointer on the system.
The size of a void* pointer will be 8 bytes or 4 bytes, respectively, on the majority of contemporary systems where memory addressing is done using 64-bit (8 bytes) or 32-bit (4 bytes) addresses.
You can use the sizeof operator to find out how big a void* reference is on your particular machine. For instance:
#include <stdio.h>
int main() {
void* genericPointer;
printf("Size of generic pointer: %zu bytes\n", sizeof(genericPointer));
return 0;
}
Output:
![Generic pointer in C](https://static.tutorialandexample.com/c/generic-pointer-in-c1.png)
The size of the void* pointer on your system in bytes will be printed when you run this programme.
How can a generic pointer be made in C?
True generic pointers are not built-in to C like they are in certain other programming languages. However, C's void pointers and macros can be used to implement a generic-like behaviour.
Here is an illustration of how to build a straightforward generic container using void pointers and macros:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
void* data;
} GenericContainer;
#define MAKE_GENERIC_CONTAINER(type) \
(GenericContainer){ .data = malloc(sizeof(type)) }
#define GET_GENERIC_VALUE(container, type) \
(*(type*)((container).data))
#define FREE_GENERIC_CONTAINER(container) \
free((container).data)
int main() {
GenericContainer intContainer = MAKE_GENERIC_CONTAINER(int);
GET_GENERIC_VALUE(intContainer, int) = 42;
GenericContainer doubleContainer = MAKE_GENERIC_CONTAINER(double);
GET_GENERIC_VALUE(doubleContainer, double) = 3.14;
printf("Integer value: %d\n", GET_GENERIC_VALUE(intContainer, int));
printf("Double value: %f\n", GET_GENERIC_VALUE(doubleContainer, double));
FREE_GENERIC_CONTAINER(intContainer);
FREE_GENERIC_CONTAINER(doubleContainer);
return 0;
}
Output
![Generic pointer in C](https://static.tutorialandexample.com/c/generic-pointer-in-c2.png)
Explanation
In this illustration, a GenericContainer structure that contains a void* pointer is defined. To construct, retrieve, and release the generic containers, we employ the macros MAKE_GENERIC_CONTAINER, GET_GENERIC_VALUE, and FREE_GENERIC_CONTAINER.
Remember that this is a very simple and basic example, and that utilising macros like this might make the code more difficult to read and maintain. Additionally, since void pointers lack type safety and inappropriate usage could result in undefinable behaviour, you should exercise caution while working with them.
Consider utilising a different language that has greater generic support if you need more intricate and type-safe generic behaviour, or look into alternative strategies like function pointers in C.
Example
#include <stdio.h>
void printValue(void* ptr, char type) {
switch (type) {
case 'i': // integer
printf("Value: %d\n", *(int*)ptr);
break;
case 'f': // float
printf("Value: %f\n", *(float*)ptr);
break;
case 'c': // char
printf("Value: %c\n", *(char*)ptr);
break;
default:
printf("Unsupported data type.\n");
}
}
int main() {
int intValue = 42;
float floatValue = 3.14;
char charValue = 'A';
printValue(&intValue, 'i'); // Output: Value: 42
printValue(&floatValue, 'f'); // Output: Value: 3.140000
printValue(&charValue, 'c'); // Output: Value: A
return 0;
}
Output
![Generic pointer in C](https://static.tutorialandexample.com/c/generic-pointer-in-c3.png)
Limitations of Void pointer:
The restrictions on generic pointers (sometimes known as "void*" pointers) in C are as follows:
1. Type safety is lacking: There is no compile-time type verification, which could result in runtime issues.
2. Explicit type casting: Requires explicit type casting when accessing data, which makes the code harder to read.
3. The pointer does not store the size of the data, which can cause memory problems.
4. Limited pointer manipulation capabilities; no pointer arithmetic.
5. Complicated debugging: Errors may only be found during runtime.
6. Loss of type-specific compiler optimisations: Without type knowledge, compiler optimisations are constrained.
7. Lack of polymorphism: It is difficult to implement genuine generic behaviour in C because it lacks built-in support for polymorphism.