Rules for using the void keyword:
1. If the function has no return value, it should be declared as void type;
2. If the function has no parameters, its parameters should be declared as void; 3. If the function parameters It can be a pointer of any type, then its parameter should be declared as void * ;
4. void cannot represent a real variable;
void embodies an abstraction, and all variables in this world are "typed"
################################################# #######################
1. Overview
Many beginners do not understand the void and void pointer types in the C/C++ language, so when using Some errors occurred. This article will explain the profound meaning of the void keyword, and detail the usage and techniques of void and void pointer types.
2. The meaning of void
The literal meaning of void is "typeless", void * is "untyped pointer", and void * can point to any type of data.
void almost only has the function of "commenting" and limiting the program, because no one has ever defined a void variable, let's try to define it:
void a;
This line of statement will cause an error when compiling, prompting "illegal use of type 'void'". However, even if void a compiles without errors, it has no practical meaning.
The real role of void is:
(1) Limitation on function returns;
(2) Limitation on function parameters.
We will explain the above two points in detail in the third section.
As we all know, if the types of pointers p1 and p2 are the same, then we can directly assign values to each other between p1 and p2; if p1 and p2 point to different data types, you must use the forced type
conversion operator to change the right side of the assignment operator The pointer type is converted to the type of the left pointer.
For example:
float *p1;
int *p2;
p1 = p2;
The statement p1 = p2 will cause a compilation error, prompting "'=' : cannot convert from 'int *' to 'float *'", It must be changed to:
p1 = (float *)p2;
Unlike void *, any type of pointer can be directly assigned to it without casting:
void *p1;
int *p2;
p1 = p2;
But this does not mean that void * can also be assigned to pointers of other types without casting. Because "typeless" can include "typed", but "typed" cannot include "typeless". The reason is very simple. We can say "men and women are human beings", but we cannot say "people are men" or "people are women". The following statement compiles error:
void *p1;
int *p2;
p2 = p1;
The prompt "'=' : cannot convert from 'void *' to 'int *'".
3. Use of void
The following are the rules for using the void keyword:
Rule 1 If the function does not return a value, it should be declared as void type
In C language, any function without return value type limitation , will be processed by the compiler as a return integer value. But many programmers mistakenly think that it is a void type. For example:
add (int a, int b)
{
return a + b;
}
int main(int argc, char* argv[])
{
printf ( "2 + 3 = %d", add ( 2, 3) );
}
The result of running the program is the output:
2 + 3 = 5
This shows that the function without return value description is indeed an int function.
Dr. Lin Rui mentioned in "High-Quality C/C++ Programming": "The C++ language has very strict type safety checks and does not allow the above situation (referring to functions without type declarations) to occur." However, the compiler does not necessarily think so. For example, in Visual C++6.0, the above add function compiles without errors or warnings and runs correctly, so we cannot rely on the compiler to do strict type checking.
Therefore, in order to avoid confusion, when we write C/C++ programs, we must specify the type of any function without missing a beat. If the function does not return a value, it must be declared as void class
type. This is not only a requirement for good readability of the program, but also a requirement for programming standardization. In addition, adding the void type declaration can also play the role of "self-annotation" of the code. The "self-annotation
interpretation" of the code means that the code can annotate itself.
Rule 2 If the function has no parameters, then its parameters should be declared as void
Declaring a function like this in C++ language:
int function(void)
{
return 1;
}
Then the following call is Illegal:
function(2);
Because in C++, the function parameter being void means that the function does not accept any parameters.
We compile in Turbo C 2.0:
#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
}
Compiled correctly and output 1, which shows that in C language, any type of parameters can be passed to a parameterless function, but in An error will occur when compiling the same code in a C++ compiler. In C++
, you cannot pass any parameters to a parameterless function, and the error message "'fun' : function does not take 1 parameters" will appear.
Therefore, whether in C or C++, if the function does not accept any parameters, the parameters must be specified as void.
Rule 3 Be careful when using void pointer types
According to ANSI (American National Standards Institute) standards, 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 for algorithmic 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). (Tested on VC6.0, it is a multiple of sizeof(int))
But the famous GNU (abbreviation for GNU's Not Unix) does not think so. It specifies that the algorithm operation of void * is consistent with char *.
Therefore, 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. (The test on VC6.0 is a multiple of sizeof(int))
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: wrong; 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 design in real life, we should still cater to the
ANSI standard as much as possible.
Rule 4 If the parameters of a function can be pointers of any type, then the parameters should be declared as void *
Typical function prototypes such as memory operation functions memcpy and memset are:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
In this way, any type of pointer can be passed into memcpy and memset, which also truly reflects the memory operation function Meaning, because the object it operates is just 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 a
"pure, free from low-level fun" function!
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 pointers of any type
int intarray1[100], intarray2[100];
memcpy (intarray1, intarray2, 100*sizeof(int)); //Copy intarray2 to intarray1
Interestingly, memcpy and memset What the function returns is also void * type. How knowledgeable the writers of the standard library functions are!
Rule 5 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:
void a; // Error
function (void a); // Error
void embodies an abstraction. Variables in this world are all "typed". For example, a person is either a man or a woman (and a shemale?).
The appearance 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.
4. Summary
Small void contains a lot of design philosophy. As a programmer, we will benefit a lot from thinking about the problem at a deeper level. No matter what type of pointer (void*, char*, int*, float*...) the default initial value is 0xCCCCCCCC//This should be different for each compiler, this is for vc6
#include
#include
//#include
void main()
{
void *p1;
int a = 10;
int *p2 = &a;
cout << ; p1 << endl;
cout << (int)*p2 << endl;
p1 = p2;
cout << *(int*)p1 << endl;// !!!!!! Use empty type operation to output value!
cout << (int)*p2 << endl;
}
/* Output:
0xCCCCCCCC
10
10
10
*/
Assign NULL at the same time of declaration and set to NULL immediately after delete .
The default initial value of the pointer in the debug version is 0xCCCCCCCC, and the initial value in the Release version is 0x0000000A (VC6.0 on my computer). If there is no suitable initialization value for the pointer, it should be set to NULL (0).
For good programming habits, declare a pointer and initialize it to NULL. If it is a class member, initialize it in the constructor. When using delete on the pointer, set it to NULL.
0xCCCCCCCC is only in debug state The undefined pointer value generated by VC below is used to indicate that this pointer has not been initialized and will not be equal to this value in the release state (unless it is a coincidence). If there is no suitable initialization value for the pointer, it should be set to NULL (0).