1. Overview
Many beginners do not understand the void and void pointer types in C/C ++, so some errors have occurred in usage. This article will describe the profound meaning of the void keyword and describe how to use the void and void pointer types.
2. Meaning of Void
Void literally means "no type", void * is "no type Pointer", and void * can point to any type of data.
Void has almost only "Comments" and restrictions on the role of the program, because no one will ever define a void variable, let's try to define:
Void;
An error occurs when compiling this line of statements, and the message "illegal use of type 'void'" is displayed '". However, even if the compilation of void a does not go wrong, it has no practical significance.
Void actually plays the following role:
(1) Restrictions on function return;
(2) Restrictions on function parameters.
We will describe the above two points in section 3.
As we all know, if the pointer P1 and P2 are of the same type, 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 convert the pointer type on the right of the value assignment operator to the pointer type on the left.
For example:
Float * P1;
Int * P2;
P1 = P2;
The p1 = P2 statement will cause compilation errors and the prompt "'=': cannot convert from 'int * 'to 'float *'" must be changed:
P1 = (float *) P2;
2 Back to Top
Void * is different. pointers of any type can be directly assigned to it without forced type conversion:
Void * P1;
Int * P2;
P1 = P2;
However, this does not mean that void * can also be assigned to other types of pointers without force type conversion. Because "No type" can tolerate "type", while "type" cannot tolerate "No type ". The principle is simple. We can say that "both men and women are people", but not "people are men" or "people are women ". The following statement compilation error:
Void * P1;
Int * P2;
P2 = p1;
The message "'=': cannot convert from 'void * 'to 'int *' is displayed *'".
3. Use of Void
The following describes the rules for using the void Keyword:
Rule 1 if the function does not return a value, the void type should be declared.
In C language, any function without a limited return value type will be processed by the compiler as the return integer value. However, many programmers mistakenly think it is of the 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 program running result is output:
2 + 3 = 5
This indicates that the function without return values is indeed an int function.
Dr. Lin Rui mentioned in "High Quality C/C ++ programming": "The C ++ language has strict type security checks and does not allow the above situations (that is, the function does not add a type declaration) occurred ". However, the compiler does not necessarily think so. For example, in Visual C ++ 6.0, the compilation of the add function is error-free and has no warning and runs correctly, therefore, we cannot expect the compiler to perform strict type checks.
Therefore, in order to avoid confusion, when writing C/C ++ programs, you must specify the type of any function. If the function does not return a value, it must be declared as void. This is both a need for good program readability and a requirement for standardized programming. In addition, after adding the void type declaration, you can also use the "self-annotation" function of the Code. The "self-annotation" of the code means that the code can annotate itself.
3 Back to Top
Rule 2 If the function has no parameters, the parameter should be declared as void
Declare a function in C ++:
Int function (void)
{
Return 1;
}
The following call is invalid:
Function (2 );
In C ++, the function parameter void means that this 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 ();
}
Compiling is correct and 1 is output. In C, parameters of any type can be transferred to a function without parameters. However, compiling the same code in C ++ compiler will cause an error. In C ++, no parameters can be transferred to a function without parameters. If an error occurs, the system prompts "'fun ': function does not take 1 Parameters ".
Therefore, whether in C or C ++, if the function does not accept any parameters, you must specify the parameter as void.
Rule 3 be careful when using the void pointer type
According to the ANSI (American National Standards Institute) standard, you cannot perform algorithm operations on the void pointer, that is, the following operations are invalid:
Void * pvoid;
Pvoid ++; // ANSI: Error
Pvoid + = 1; // ANSI: Error
// The ANSI standard determines this because it insists that the pointer to the algorithm operation must be determined to know the data type it points.
// Example:
Int * pint;
Pint ++; // ANSI: Correct
The result of pint ++ is to increase sizeof (INT ).
However, the well-known GNU (GNU's not UNIX abbreviation) does not recognize this as it specifies that the void * algorithm operation is consistent with char.
4 Back to Top
Therefore, the following statements are correct in the GNU Compiler:
Pvoid ++; // GNU: Correct
Pvoid + = 1; // GNU: Correct
The execution result of pvoid ++ is increased by 1.
In actual programming, to cater to ANSI standards and improve program portability, we can write code that implements the same function as below:
Void * pvoid;
(Char *) pvoid ++; // ANSI: Correct; GNU: Correct
(Char *) pvoid + = 1; // ANSI: error; GNU: Correct
There are some differences between GNU and ANSI. In general, GNU is more open than ANSI and provides support for more syntaxes. However, in actual design, we should try to cater to ANSI standards as much as possible.
Rule 4 if the function parameter can be a pointer of any type, the parameter should be declared as void *
Typical function prototypes for memory operation functions such as 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 truly reflects the significance of the memory operation function, because the object it operates on is only a piece of memory, regardless of the memory type. If the parameter types of memcpy and memset are not void * But char *, it is really strange! Such memcpy and memset are obviously not "pure, out of low-level interests" functions!
5 Back to Top
The following code is correctly executed:
// Example: memset accepts any type of pointer
Int intarray [100];
Memset (intarray, 0,100 * sizeof (INT); // clear intarray 0
// Example: memcpy accepts any type of pointer
Int intarray1 [100], intarray2 [100];
Memcpy (intarray1, intarray2, 100 * sizeof (INT); // copy intarray2 to intarray1
Interestingly, the memcpy and memset functions also return the void * type. how knowledgeable are the compilers of the standard library functions!
Rule 5 void cannot represent a real Variable
The following code tries to make void represent a real variable, so it is all wrong code:
Void A; // Error
Function (void a); // Error
Void represents an abstraction in which all variables in the world are "typed". For example, a person is either a man or a woman (or a demon ?).
The emergence of void is only for an abstract need. If you have understood 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 for an abstract base class, we cannot define a void (let's say that void is an abstract data type) variable.
4. Summary
The small void contains a wealth of design philosophy. As a program designer, thinking deeply about the problem will inevitably benefit us a lot.