- Forum
- General Programming Boards
- C Programming
- Warning:dereferencing `void *’ pointer
-
04-26-2007
#1
Registered User
Warning:dereferencing `void *’ pointer
Hi again!
In my program i have declared a function with this prototype:
Code:
int function(void *var) //The second argument is a void * pointer Also i have a struct typedef struct hello hello; struct hello { char *a; char *b; int l; int t; struct hello *next; }; hello *pointer_hello;
When i do: function(pointer_hello);
I get the warnings:
warning: dereferencing `void *’ pointer
test.c:516: error: request for member `a’ in something not a structure or union
warning: dereferencing `void *’ pointer
test.c:517: error: request for member `b’ in something not a structure or union
warning: dereferencing `void *’ pointer
test.c:518: error: request for member `l’ in something not a structure or union
warning: dereferencing `void *’ pointer
test.c:519: error: request for member `t’ in something not a structure or unionWhat shall i change in my program?
Well the problem is that the argument of the function «function» has to be void in order
not only to take a pointer to a hello struct but to any other struct!Thanks, in advance!
-
04-26-2007
#2
and the hat of int overfl
It’s impossible to tell, since we need the actual order in which you declared things, and in which file(s) they reside.
-
04-26-2007
#3
Deathray Engineer
My guess is that you are passing a struct pointer to a function that is defined to take a void pointer. You must cast the void pointer to be that of a struct pointer before actually dereferencing it. The compiler has no idea what a void pointer is pointing to. With regard to size, it could be pointing to a byte, a word, a double word, etc. etc. There is no known way of it knowing you are passing it a struct pointer.
In this case, you must be explicit when dealing with void *’s.
-
04-26-2007
#4
Registered User
i do
Code:
#define int function( void * var ) ; typedef struct hello hello; struct hello { char *a; char *b; int l; int t; struct hello *next; };
Then it starts
Code:
int main() { hello *pointer_hello; function(poinet_hello); }
That’s all!
-
04-26-2007
#5
Registered User
-
04-26-2007
#6
and the hat of int overfl
> #define int function( void * var ) ;
What the hell is this supposed to mean?Make function accept an hello* and be done with it.
-
04-26-2007
#7
Registered User
Originally Posted by MacGyver
My guess is that you are passing a struct pointer to a function that is defined to take a void pointer. You must cast the void pointer to be that of a struct pointer before actually dereferencing it. The compiler has no idea what a void pointer is pointing to. With regard to size, it could be pointing to a byte, a word, a double word, etc. etc. There is no known way of it knowing you are passing it a struct pointer.
In this case, you must be explicit when dealing with void *’s.
How can i do this cast?
can you make an example using the example i have given?Thanks, in advance!
-
04-26-2007
#8
Deathray Engineer
Code:
struct x { int a; }; ... int example(void *p) { struct x *q; if(p) { q = (struct x *)p; /* Explicit cast from a void * to a struct x * */ q.a = 5; return 1; } return 0; } ... int main(void) { struct x v1; example(&v1); return 0; }
Note: I did not check this code. I would suggest doing what was already suggested: just make your function accept a *hello.
-
04-26-2007
#9
Registered User
dont use void * pointer for this purpose. It looks really messy for evert struct that u wanted to refer you will have to cast it.
It better u get the argument as struct hello * rather than void *. Which is quite more easy than void. If there are suitation some thing like where a single function need to do the same job for two different struct with same attributes but different names then may be u can think of void pointer.
ssharish2005
Popular pages
- Exactly how to get started with C++ (or C) today
- C Tutorial
- C++ Tutorial
- 5 ways you can learn to program faster
- The 5 Most Common Problems New Programmers Face
- How to set up a compiler
- 8 Common programming Mistakes
- What is C++11?
- Creating a game, from start to finish
Recent additions
- How to create a shared library on Linux with GCC — December 30, 2011
- Enum classes and nullptr in C++11 — November 27, 2011
- Learn about The Hash Table — November 20, 2011
- Rvalue References and Move Semantics in C++11 — November 13, 2011
- C and C++ for Java Programmers — November 5, 2011
- A Gentle Introduction to C++ IO Streams — October 10, 2011
Similar Threads
-
Replies: 5
Last Post: 06-26-2008, 10:10 AM
-
Replies: 15
Last Post: 06-01-2008, 03:47 PM
-
Replies: 15
Last Post: 08-12-2006, 07:12 AM
-
Replies: 10
Last Post: 04-09-2006, 03:36 AM
-
Replies: 20
Last Post: 10-09-2003, 12:04 PM
What are void pointers in C?
A void pointer is a pointer that has no specific data type associated with it. Therefore, it can point to a variable of any data type. Void pointers are valid in C.
Declaring void pointers:
void *pointerName;
- void indicates that the pointer is a void pointer
- * indicates that the variable is a pointer variable
- pointerName is the name of the pointer
Let us look at an example of declaring and initializing void pointer in C:
void *ptr;
char ch = ‘N’;
int num = 10;
ptr = &ch;
ptr = #
In the above code, we notice that since ptr is a void pointer, we can make it point to a variable of char type as well as a variable of int type. It can point to any type of variables.
Some important points to remember while using void pointers:
- A void pointer cannot be dereferenced. We get a compilation error if we try to dereference a void pointer. This is because a void pointer has no data type associated with it. There is no way the compiler can know what type of data is pointed to by the void pointer. The solution is typecasting. To get the data pointed to by a void pointer we typecast it with the correct type of the data held inside the void pointers location.
Let us understand this with a code:
#include<stdio.h>
void main()
{
int num=10;//Intialising a normal varible
void *ptr;//Declaring a void pointer
ptr=#//Making ptr point to num
printf("The value of integer variable is= %d",*ptr );
}
When we run this code, we get a compilation error as follows:
exit status 1
main.c: In function 'main':
main.c:13:49: warning: dereferencing 'void *' pointer
printf("The value of integer variable is= %d",*ptr );
^~~~
main.c:13:49: error: invalid use of void expression
Look at us look at the same code. We use typecasting here to dereference the pointer:
#include<stdio.h>
void main()
{
int num=10;//Intialising a normal varible
void *ptr;//Declaring a void pointer
ptr=#//Making ptr point to num
printf("The value of integer variable is %d", (int)ptr );// Typecasting
}
The output will be:
The value of integer variable is 10
Therefore, by typecasting, we can dereference void pointers.
- Pointer arithmetic is not allowed with a void pointer, it gives an error.
Uses of void pointers:
- Void pointers are used in Generic functions in C.
- malloc() and calloc() functions return void * type. This allows these functions to allocate memory to any data type.
vani2 0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
||||||||
1 |
||||||||
04.04.2011, 22:13. Показов 3932. Ответов 15 Метки нет (Все метки)
Написал программу, но ошибки в присваивании с раскрытием указателя на void. В gcc: В Borland 5.02: Подскажите как исправить, чтоб правильно заработало. header:
new.c:
__________________
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
04.04.2011, 22:13 |
15 |
В астрале 8048 / 4805 / 655 Регистрация: 24.06.2010 Сообщений: 10,562 |
|
04.04.2011, 23:50 |
2 |
vani2, нельзя так void раскрывать. только после приведения к конкретному типу.
0 |
vani2 0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
||||
05.04.2011, 09:24 [ТС] |
3 |
|||
Хорошо…
Выдаёт непонятную ошибку (наверное, всё кроется в отсутствии «»).
0 |
Делаю внезапно и красиво 1312 / 1227 / 72 Регистрация: 22.03.2011 Сообщений: 3,744 |
|
05.04.2011, 09:29 |
4 |
к какому типу мне приводить, чтобы не терять значение ? А какой тип ты в нём сохранял? Вот к нему и приводи.
0 |
vani2 0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
||||
05.04.2011, 09:42 [ТС] |
5 |
|||
В том то и дело, что я наперёд не знаю, какой тип там будет храниться. Лишь знаю array->tsize-размер элемента в байтах. Ещё не могу понять, почему эта функция не работает:
/mingw/lib/libmingw32.a(main.o):main.c.text+0xd2): undefined reference to `Win
0 |
14 / 14 / 1 Регистрация: 04.04.2011 Сообщений: 70 |
|
05.04.2011, 09:54 |
6 |
для копирования попробуй memncpy
0 |
0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
|
05.04.2011, 10:09 [ТС] |
7 |
для копирования попробуй memncpy Ты имеешь ввиду memcpy? Над твоим постом результат применения-неудача.
0 |
14 / 14 / 1 Регистрация: 04.04.2011 Сообщений: 70 |
|
05.04.2011, 10:10 |
8 |
да, пардон, опечатка.
0 |
0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
|
05.04.2011, 13:00 [ТС] |
9 |
Какие будут ещё предложения?
0 |
В астрале 8048 / 4805 / 655 Регистрация: 24.06.2010 Сообщений: 10,562 |
|
05.04.2011, 14:26 |
10 |
vani2, В чем суть программы? Если данные разных типов надо хранить — то стоит завести некую структуру тип, а дальше уже через switch…
1 |
0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
|
05.04.2011, 15:24 [ТС] |
11 |
Я пишу динамический массив произвольного типа.
Ты тут явно тип указываешь, мне так нельзя ( то есть я не знаю к какому типу приводить, думаю всё к char* писать ). От данной структуры программы я отходить не могу, так что с указателями на void придётся делать.
0 |
Делаю внезапно и красиво 1312 / 1227 / 72 Регистрация: 22.03.2011 Сообщений: 3,744 |
|
05.04.2011, 15:48 |
12 |
думаю всё к char* писать Не получится. Вернее получится, но потом не удивляйся тому, что увидишь.)
0 |
vani2 0 / 0 / 0 Регистрация: 05.12.2010 Сообщений: 20 |
||||
05.04.2011, 16:25 [ТС] |
13 |
|||
Написал вот так:
Всё отлично работает. Осталось этот алгоритм в свой проект вставить.
0 |
Делаю внезапно и красиво 1312 / 1227 / 72 Регистрация: 22.03.2011 Сообщений: 3,744 |
|
05.04.2011, 17:00 |
14 |
Строки 15,16 что делают?
0 |
wolf.diesel 14 / 14 / 1 Регистрация: 04.04.2011 Сообщений: 70 |
||||||||||||
05.04.2011, 17:14 |
15 |
|||||||||||
Это бесполезный код.
Это
Замени на
0 |
Делаю внезапно и красиво 1312 / 1227 / 72 Регистрация: 22.03.2011 Сообщений: 3,744 |
|
05.04.2011, 17:21 |
16 |
Замени на Заменять не нужно. Тип определяется только формтной строкой.
0 |
- Forum
- Beginners
- error: invalid use of void expression
error: invalid use of void expression
CodeBlocks…
warning: dereferencing ‘void *’ pointer [enabled by default]|
error: invalid use of void expression
I believe i do not know how to properly use the generic void* pointer. I want to pass data to pointer to void so that to be able to manipulate any type of data the user wants to use. The functions below is just a test to show my intentions.
I am using only c language syntax. I do not want c++ syntax for these.
I have asked a very similar question in the past but i did not quite get it. It was not the kind of response i was hoping for.
|
|
e]
5:6: error: ‘void*’ is not a pointer-to-object type
6:6: error: ‘void*’ is not a pointer-to-object type
6:11: error: ‘void*’ is not a pointer-to-object type
In function ‘void* foo1(void*)’:
11:4: error: ‘void*’ is not a pointer-to-object type
11:9: error: ‘void*’ is not a pointer-to-object type
11:15: warning: no return statement in function returning non-void [-Wreturn-type]
Normally when using void pointers, one has to cast the pointer to a type.
http://stackoverflow.com/questions/16986214/why-type-cast-a-void-pointer#16986872
When doing some kind of operation on data the compiler needs to know the type, otherwise it doesn’t know what machine code to generate. For example, addition between two signed 32-bit integers uses a different CPU instruction than addition between two unsigned 16-bit integers, or between two floating point numbers. Addition between two class types requires that the correct overload of operator+ is called, but if the compiler doesn’t know the types there is no way it could know which overload to call.
If you can use C++ features you might find function templates useful. The compiler will then be able to automatically generate code (at compile time) for each type that you pass to it.
|
|
Last edited on
Cast your pointer to the desired type before manipulating it.
The problem with foo()
is that there are non-enforceable requirements on the real type of the pointed-to object. You either need to know the type is (i.e., by passing it in as a macro parameter or via a printf-style specifier), or you need to make assumptions about the type based on its size, and you’d have to pass the size in.
The real solution is to not use void* here. Generic programming in C is awful.
Is something like this what you’re thinking of?
|
|
http://coliru.stacked-crooked.com/a/5c5f42258e8f2c92
Last edited on
Topic archived. No new replies allowed.
In this article, we will learn what is void pointer in C and how we can use void pointer in our C code. If you are new in c programming, you should read this article “C pointer concept“. In the C language pointer is used to store the address of any variable or function but we need to remember that types of the pointer should be the same as the types of the pointed object (variable, pointer, array, function …etc.).
For example, if you want to store the address of the character, the pointer should be a pointer to the character.
char cData; char *pcData = NULL; pcData = &cData;
To resolve the above problem, C language introduces a generic type of pointer (void pointer) that can store the address of any type.
What is void pointer in C?
A void pointer in c is called a generic pointer, it has no associated data type. It can store the address of any type of object and it can be type-casted to any type. According to C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type. A void pointer declaration is similar to the normal pointer, but the difference is that instead of data types we use the void keyword.
Syntax:
void * Pointer_Name;
Example,
void *pvHandle;
What is the size of a void pointer in C?
The size of a void pointer is similar to the size of the character pointer. According to C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type.
The size of the pointers depending on the platform and it can be 2bytes, 4bytes or 8bytes …etc.
Let’s see some example code.
#include <stdio.h> int main(int argc, char *argv[]) { void *pvData = NULL; //void pointer int *iData = NULL;// integer pointer char *cData = NULL;//character pointer float *fData = NULL;//float pointer //size of void pointer printf("size of void pointer = %dnn",sizeof(pvData)); //size of void pointer printf("size of integer pointer = %dnn",sizeof(iData)); //size of void pointer printf("size of character pointer = %dnn",sizeof(cData)); //size of void pointer printf("size of float pointer = %dnn",sizeof(fData)); return 0; }
Output: On a 32-bit machine
size of void pointer = 4 size of integer pointer = 4 size of character pointer = 4 size of float pointer = 4
Dereferencing a void pointer in C
Using the indirection operator (*) we can get back the value which is pointed by the pointer, but in case of void pointer we cannot use the indirection operator directly. This is because a void pointer has no data type that creates a problem for the compiler to predict the size of the pointed object. So before dereferencing the void * we have to typecast it, it enables the compiler to predict the data types.
Let’s see some example code.
#include <stdio.h> int main(int argc, char *argv[]) { void *pvData; int iData = 10; pvData = &iData; printf("*pvData = %d",*pvData); return 0; }
Explanation: When we compile the above code, we will get the compiler error because in the above code I tried to dereference the void pointer without type casing.
But what happened if we type-cast the void pointer, its working fine see the below example code.
#include <stdio.h> int main(int argc, char *argv[]) { void *pvData; int iData = 10; pvData = &iData; printf("iData = %d",*(int*)pvData); return 0; }
Output: 10
In the above code void pointer, pvData is pointing to the address of iData (integer variable). So to access the value of integer variable (iData) through the void pointer we have to typecast void pointer through the integer pointer.
(int *)pvData;
Now above expression behave like an integer pointer. You already know how to dereference an integer pointer using an indirection operator (*).
*(int *)pvData
Now you will get the value of the integer which addresses pointed by the void pointer.
Why are void pointers use?
A very important feature of the void pointer is reusability. Using the void pointer we can store the address of any object and whenever required we can get back the object through the indirection operator with proper casting.
Let’s take an example,
#include <stdio.h> int main(int argc, char *argv[]) { void *pvData; int iData = 10; char cData = 'A'; float fData = 27.6; //Assigning address of character pvData = &cData; //dereferencing void pointer with character typecasting printf("cData = %cnn",*((char*)pvData)); //Assigning address of integer pvData = &iData; //dereferencing void pointer with integer typecasting printf("iData = %dnn",*((int *)pvData)); //Assigning address of float pvData = &fData; //dereferencing void pointer with float typecasting printf("fData = %fnn",*((float *)pvData)); return 0; }
Output:
cData = A iData = 10 fData = 27.600000
Explanation: In the above code, pvData is a void pointer. Using it I am storing the address of the different variables (float, int, and char) and after that getting back their values using the indirection operator and proper typecasting.
You can see in the example code, how a single pointer is dealing with different types of variables. This is a very interesting feature of the void pointer that makes the programmer helpless to use the void pointer.
If you want to learn more about the c language, here 10 Free days (up to 200 minutes) C video course for you.
Arithmetic operation on void pointers
Here I want to mention an important point about the arithmetic operation on a void pointer. If you will directly perform an arithmetic operation on the void pointer you may get unexpected results. So you should perform proper typecasting on the void pointer before performing the arithmetic operation.
#include<stdio.h> int main() { //integer array int aiData[3] = {100, 200,300}; //assigned first element address to the void pointer void *pvData = &aiData[0]; printf(" pvData = %lun", pvData); printf(" pvData+1 = %lun", pvData +1); //Incorrect return 0; }
When you will run the above code you will get the unexpected result.
Since the array (aiData) is the collection of integer element so the type of &aiData[0] would be a pointer to int (int*). So we have to typecast the void pointer pvData from the pointer to int (int*) before performing an arithmetic operation.
#include<stdio.h> int main() { //integer array int aiData[3] = {100, 200,300}; //assigned first element address to the void pointer void *pvData = &aiData[0]; printf(" pvData = %lun", pvData); printf(" pvData+1 = %lun", (int*)pvData +1); //Correct return 0; }
Output:
You can see, showing the correct value. In my case, the integer size is 4 byte.
Application of void pointer in C
Application of void pointers are very wide, we can not cover all the application in one article. Here I am taking one of the most popular applications of the void pointer in qsort function.
A qsort is a C standard library function that is used to sort arrays. Using the qsort function, we can sort the array of integer, double, long, etc.
Following is the declaration for qsort() function,
void qsort(void *arr, size_t elements, size_t size, int (*comp)(const void *, const void*));
Parameters of qsort:
arr − pointer to the first element of the array.
elements − number of elements in the array.
size − size(in bytes) of the element in the array.
comp − compare function that is used to compares two elements.
int comp(const void* a, const void* b);
Let see an example code to understand the working of qsort and importance of void pointer:
In this example code, I am showing how is the qsort function sort any type of array with the help of compare function.
#include <stdio.h> #define ELEMENT_SIZE(x) sizeof(x[0]) #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) //compare function for intger array int compareInt(const void *a, const void *b) { int x = *(const int *)a; int y = *(const int *)b; if (x < y) return -1; //-1 for ascending, 1 for descending order. else if (x > y) return 1; //1 for ascending, -1 for descending order. return 0; } //compare function for float array int compareFloat(const void *a, const void *b) { float x = *(const float *)a; float y = *(const float *)b; if (x < y) return -1; //-1 for ascending, 1 for descending order. else if (x > y) return 1; //1 for ascending, -1 for descending order. return 0; } int main(int argc, char *argv[]) { //Integer array int iData[] = { 40, 10, 100, 90, 20, 25 }; //float array float fData[] = {1.2,5.7,78,98.5,45.67,81.76}; //array index int index = 0; //sorting integer array qsort(iData,ARRAY_SIZE(iData),ELEMENT_SIZE(iData),compareInt); for (index=0; index<ARRAY_SIZE(iData); index++) { printf ("%d ",iData[index]); } printf("nn"); //sortig float array qsort(fData,ARRAY_SIZE(fData),ELEMENT_SIZE(fData),compareFloat); for (index=0; index<ARRAY_SIZE(fData); index++) { printf ("%f ",fData[index]); } return 0; }
Output:
10 20 25 40 90 100 1.200000 5.700000 45.669998 78.000000 81.760002 98.500000
Disadvantages of the void pointer in C
- Like the other pointers, we cannot dereference the void pointers because the compiler does not have any information about the pointed object. If we try to compile the below code then we will get the compiler error.
#include<stdio.h> int main() { int iData = 100; void *piData = &iData; printf("%d", *piData); return 0; }
But with proper typecasting, we can dereference the void pointer and get back the value of the pointed address.
#include<stdio.h> int main() { int iData = 1000; void *piData = NULL; piData = &iData; printf("%d", (*(int*)piData)); return 0; }
- According to c standard arithmetic operation on void pointers is illegal that means the C standard doesn’t allow pointer arithmetic with void pointers. However, In GNU C, addition and subtraction operations are supported on void pointers to assuming the size of the void is 1.
#include<stdio.h> int main() { int aiData[3] = {100, 200,300}; void *pvData = &aiData[1]; //address of 200 pvData += sizeof(int); printf("%d", *(int *)pvData); return 0; }
Output: 300 or compiler error.
Explanation: When we compile the code then some compiler throw the compiler error but some compiler compiled the code and print 300 as output to assume the size of the void 1.
Note: Don’t perform the arithmetic operation on the void pointer. As per the C standard sizeof is not applicable on void but in GNU C we can calculate the size of the void and sizeof operator return 1.
Advantages of the void pointer in c
- Using the void pointer we can create a generic function that can take arguments of any data type. The memcpy and memmove library function are the best examples of the generic function, using these function we can copy the data from the source to destination.
Below code shows the implementation of memcpy in C
int Memcpy(void* dst, const void* src, unsigned int cnt) { uint8_t *pszDest = (uint8_t *)dst; const uint8_t *pszSource =( const uint8_t*)src; while(cnt) { *(pszDest++)= *(pszSource++); cnt--; } return 0; }
Using the memcpy we can copy the string, as well as the array of integers, see the below example codes.
#include<stdio.h> int main() { char *pszMessage = "Welcome to aticleworld!";//Source String char aszDisplayMessage[32]= {0}; //Destination string short siLenString=0; // siLenString = strlen(pszMessage)+1; // length of source string Memcpy(aszDisplayMessage, pszMessage,siLenString );//copy source to destination printf("Message = %sn", aszDisplayMessage); return 0; }
#include<stdio.h> int main(void) { int iLoop = 0; int aiSrc [5] = {100,200,300,400,500};//integer array int aiDst[5]= {0}; //Destination array Memcpy(aiDst, aiSrc,sizeof(aiSrc));//copy integer array for(iLoop =0; iLoop <5 ; iLoop++) //print { printf("%d ",aiDst[iLoop]); } return 0; }
You can see how memcpy is working here as a generic copy function with the help of a void pointer.
- We know that void pointer can be converted to another data type that is the reason malloc, calloc or realloc library function return void *. Due to the void * these functions are used to allocate memory to any data type.
- Using the void * we can create a generic linked list. For more information see this link: How to create generic Link List.
You want to learn more about C Pointers, you can check the below articles.
- A brief description of the pointer in C.
- Dangling, Void, Null and Wild Pointers
- Function pointer in c, a detailed guide
- How to use the structure of function pointer in c language?
- Function pointer in structure.
- Pointer Arithmetic in C.
- 10 questions about dynamic memory allocation.
- Memory Layout in C.
- 100 C interview Questions
- File handling in C.
- C format specifiers.
I have some functions which take as i/p a buffer (it can be float, char,
or 16 bit, int etc.). The result is another o/p buffer, its type is also
flexible (it could be a float, char etc.).I try to pass both as «void *buf» so that it can accept any data type.
But since I access the buffer and try to assign its elements to another
I get compile errors (I have pasted at the end).Now my question is how can I pass the i/p and o/p buffers as args to the
function without hardcoding the data type, someone earlier suggested to
pass another argument which tells the type, e.g.
myfunction(void * buf, 1, …) 1 may indicate that buf is char type, 2
means 16 bit etc.But that means having if .. else’s inside the function to do the same
thing. Is there any other way?
Here is a bit pattern, 32 bits long:
11000101001110101001110101000110
What does it mean? What value(s) does it represent?
Does your answer change if I tell you it is the raw bits of a 32-bit
«float»? What if I say it is a 32-bit VAX float, or perhaps a 32-bit
SPARC float? Suppose I say it is, instead, a 32-bit «int», or a
32-bit «signed int». Now what value(s) can it represent? What if
it is an array of four «char»s or four «unsigned char»s?
(Finding answers — there may be more than one — to the above
questions is a good and useful exercise, that will help you understand
how the system(s) you use interpret bits. Note that different
systems interpret the same bits differently! One reason we use
«high level» source code — although C is relatively low level for
a high level language — is to avoid having to specify the precise
set of bits, which change from system to system, when we can get
away with specifying only what we want the bits to mean. The
source-code number «3.1415» or «42» has a definite meaning, and
the fact that machines A and B use different bit-patterns to
represent them is — we hope — irrelevant.)
Note that all of these are 32 bits long. They all look exactly the
same when treated as a 32-bit-long bit-string. But they all represent
different values.
When you use «void *» in C, you are — usually — implicitly using
a «bag of uninterpreted bits» type. Any interpretation necessarily
arises from giving the «bag of bits» some more-specific type. You
must decide whether you intend to interpret the bits, and if so, how.
This will dictate the type(s) you must provide.
Note that a series of if/else’s, or a switch, inside a function
that receives a «void *» but wants to interpret the bits as one
of (say) the two possibilities «int» and «float» will result in C
code looking like:
enum whichtype { TY_INT, TY_FLOAT };
/*
* Here p points to the first bit(s) in the bag-o-bits, «len»
* is the number of items of some interpreted type, and «ty»
* is the enumeration saying which type.
*/
void f(void *p, size_t len, enum whichtype ty) {
size_t i;
int *ip;
float *fp;
switch (ty) {
case TY_INT:
ip = p;
… work with ip, where i is between 0 and len-1, e.g:
for (i = 0; i < len; i++)
ip *= 2;
break;
case TY_FLOAT:
fp = p;
… work with fp, where i is between 0 and len-1 …
for (i = 0; i < len; i++)
fp *= 2.0;
break;
default:
panic(«invalid type argument %d to f()», (int)ty);
/* NOTREACHED */
}
}
Not only do you really, truly have to write the if/else or switch,
you will also find that, on typical machines, it compiles to code
that uses different machine instructions to manipulate the data.
The code using ip might look like, e.g.:
# this doubles ip, where i is in %eax and ip is in %edx
movl (%edx,%eax,4),%ecx
addl %ecx,%ecx
movl %ecx,(%edx,%eax,4)
versus:
# this doubles fp, where i is in %eax and fp is in %edx
flds (%edx,%eax,4)
fadds (%edx,%eax,4)
fstps (%edx,%eax,4)
These completely-different machine instructions are utterly necessary
here — using the «addl %ecx,%ecx» instructions will not result in
doubling a «float» value in fp, but rather will just make a mess
of the value.
Thus, different C code is required because different machine code
is required. Using «void *» absolves neither you nor the compiler
of this.
If you do enough of this sort of thing (or analyse your systems
carefully), you will find that there are cases where the C source
code must be different, yet the underlying machine code on your
machine(s) is the same. This happens because (and when) the abstract
meaning defined in C for two different types happens to be implemented
using a single underlying machine-level mechanism. But in general,
the C code should remain separate, because on some *other* machine(s),
this may no longer be the case. In other words, in the C code,
you write *what* you want to have happen, not *how* to *make* it
happen. If you want different things, at the C level, that all
happen to be done the same way at the machine level, it is the
compiler’s job to discover this and optimize the code appropriately.
(Some compilers are better than others at this, and you may sometimes
find yourself having to «help» some compilers a bit. Do this only
when you really know what you are doing. )
void has no value and no size. It’s a placeholder for nothing basically.
void* is a pointer to an address in memory, but the language doesn’t know how the value there is supposed to be interpreted, because the programmer told it «a nothing is at this address» by making it a void pointer.
Dereferencing a pointer gives you the value of what’s being pointed at. If you have a char* cp, *cp gives you the value of the char at cp. But void doesn’t have value, so the compiler can’t give you anything.
void* is typically used to point to data that could be anything, but had to be treated as nothing, usually because its proper type couldn’t be known (in every compilation unit) at compile time. So we cast it to a pointer of the right type in the compilation unit that knows what type the data there is supposed to be.
C++ added a new type std::any to solve this problem of «pointing at nothing because it could be anything», because it was a type safety nightmare. std::any is basically just a wrapper around void* and std::type_info with a new type-safe casting function std::any_cast<T>. It’s a relatively recent addition so plenty of legacy void* code is still around. You still need to cast it appropriately with std::any_cast to use the data though.