The meaning of void
void is "typeless", void * is "typeless pointer", which can point to any data type.
Void pointer usage specifications
①The void pointer can point to any type of data, that is, a pointer of any data type can be used to assign a value to the void pointer. For example:
int *pint;
void *pvoid;
pvoid = pint; /* However, pint = pvoid; */
If you want to assign pvoid to another type of pointer, you need to cast it such as: pint = (int * )pvoid;
②In the ANSI C standard, arithmetic operations such as pvoid++ or pvoid+=1, etc. are not allowed on void pointers, but it is allowed in GNU, because by default, GNU considers void * and char * Same. sizeof( *pvoid )== sizeof( char ).
The role of void
① Limitation of function return.
②Limitations on function parameters.
When a function does not need to return a value, void qualification must be used. For example: void func(int, int);
When a function is not allowed to accept parameters, void qualification must be used. For example: int func(void).
Since the void pointer can point to any type of data, that is, a pointer of any data type can be used to assign a value to the void pointer, so the void pointer can also be used as a function parameter, so that the function can accept a pointer of any data type as a parameter. . For example:
void * memcpy( void *dest, const void *src, size_t len );
void * memset( void * buffer, int c, size_t num );
Many beginners are familiar with void and The void pointer type is not well understood, so some errors occurred in its use. This article will explain the profound meaning of the void keyword. The following details the usage methods and techniques of void and void pointer types.
1. Rules: Use the void pointer type with caution
According to the ANSI (American National Standards Institute) standard, arithmetic operations cannot be performed on void pointers, that is, the following operations are illegal:
void*pvoid;
pvoid++;//ANSI: Error
pvoid+ =1;//ANSI: Error
//The reason why the ANSI standard identifies this is because it insists that the pointer used for algorithm operations must know the size of the data type it points to.
//For example:
int*pint;
pint++;//ANSI: Correct
The result of pint++ is to increase sizeof(int).
But the famous GNU (abbreviation of GNU'sNotUnix) does not think so. It specifies that the algorithm operation of void* is consistent with that of char*.
So the following statements are correct in the GNU compiler:
pvoid++; //GNU: correct
pvoid+=1; //GNU: correct
The execution result of pvoid++ is that it increases by 1.
In actual programming, in order to cater to the ANSI standard and improve the portability of the program, we can write code to achieve the same function like this:
void*pvoid;
(char*)pvoid++; //ANSI: correct; GNU : Correct
(char*)pvoid+=1; //ANSI: Error; GNU: Correct
There are some differences between GNU and ANSI. Generally speaking, GNU is more "open" than ANSI and provides support for more syntaxes. But when we actually design, we should still cater to ANSI standards as much as possible.
2. Rule 2: If the parameter of a function can be a pointer of any type, then its parameter should be declared as void*
Typical function prototypes such as memory operation functions memcpy and memset are:
void*memcpy(void*dest,constvoid *src,size_tlen);
void*memset(void*buffer,intc,size_tnum);
In this way, any type of pointer can be passed into memcpy and memset, which also truly reflects the meaning of the memory operation function, because it The object of operation is only a piece of memory, regardless of what type of memory it is. It would be really strange if the parameter type of memcpy and memset is not void*, but char*! Such memcpy and memset are obviously not "pure, free from low-level fun" functions!
The following code is executed correctly:
//Example: memset accepts pointers of any type
int intarray[100];
memset(intarray,0,100*sizeof(int));//Clear intarray to 0
//Example: memcpy accepts Any type of pointer
int intarray1[100], intarray2[100];
memcpy(intarray1,intarray2,100*sizeof(int));//Copy intarray2 to intarray1
What’s interesting is that the memcpy and memset functions also return void * type, how knowledgeable the writers of the standard library functions are!
3. Rule 3 void cannot represent a real variable
The following codes are all attempts to make void represent a real variable, so they are all wrong codes:
voida;//Error
function(voida);//Error
void It embodies an abstraction. The variables in this world are all "typed". For example, a person is either a man or a woman (and a shemale?).
The emergence of void is just for an abstract need. If you correctly understand the concept of "abstract base class" in object-oriented, it is easy to understand the void data type. Just as we cannot define an instance of an abstract base class, we cannot define a void (let us call void an "abstract data type" by analogy) variable.