C ++'s template Mechanism brings great convenience to General Data Type programming. Can C language implement similar functions? Of course, you can see some library function interfaces in C. For example, the quick sort function is an example of general data type programming:
Void qsort (void * base, sizet_t nmemb, sizet_t size,
Int (* compar) (const void *, const void *); this function can sort any type of data, as long as a correct comparison function is provided.
So how do I implement general data programming in C language? This article will give a detailed explanation of this problem, and finally use the described method to implement a general data type stack.
Data commonalities
The so-called general data type programming, that is, for different types of data, the code used to complete the same operation is also the same. for example, for variable assignment operations, no matter what the actual variable type is, if the assignment operation can be completed using the same sentence, the program at this time is of the general data type. the code at this time may be: void assign (T var2, T var1). The assign function completes the assignment operation, and the value of var1 is assigned to var2, at present, T is used to represent the types of the variables var1 and var2.
When observing the assign function, we can't help but ask: if you want to assign the value of var1 to var2, simply use the statement: var2 = var1. Is it necessary to write a special function? To answer this question, you must first know the following two points:
"=" Is essentially a function. It is equivalent to var2 = var1 in the form of = (var2, var1), that is, a function named "=" that accepts two parameters.
"=" Can only be used for assigning values between regular types of data, but not for assigning values to strings, struct, and other types.
Therefore, it is necessary to write a value assignment operation for a common data type into a function. How can this function be implemented? First, we will analyze how the assignment operation of existing data types is completed:
Conventional data types. For this type of data, you can use "=" to complete the assignment between variables. But what happened in the assignment process? In fact, although the assignment statements of different data types are the same (both var2 = var1), the Operations behind them are different. for example, if var1 and var2 are of the int type, the actual effect of the statement var2 = var1 is: copy the content in the four-byte memory space occupied by var1 to the memory space occupied by var2. However, if var1 and var2 are of the char type, the actual effect of the statement var2 = var1 is: copy the content in the memory space occupied by var1 to the memory space occupied by var2 in 1 byte.
From the above analysis, we can see that the Data assignment is implemented through the replication of memory units. The number of inner storage units for replication varies depending on different data types.
The strcpy () function is used to assign values to strings. How does strcpy () assign values to character strings? A Simplified Implementation of strcpy () is as follows:
Char * strcpy (char * dest, const char * src)
{
Char * desto = dest;
While (* dest ++ = * src ++ );
Return desto;
} The Code shows that the value assignment of a string is to copy the memory space occupied by the source string to the memory space occupied by the object string.
Through the above two points of analysis, we can find a common feature: For the value assignment operation, no matter what the data type is, it is implemented through the content of the bucket, but for different data types, the number of copied memory units is different. therefore, we can implement our value assignment function based on the same idea. the question is: how to obtain the memory space occupied by the change, which is equivalent to the following two problems:
How to get the starting address of the memory space occupied by the variable;
How to obtain the number of units in the memory space occupied by the variable.
In the following content, we will answer these two questions one by one.
Void pointer
It is very easy to get the starting address of a variable, because the C language provides a special operator: "&", get the address operator. we can save the address in a pointer for ease of use. but the problem is: because we want to implement general data type programming, and the actual operand type is a specific data type, so what type of pointer variable should we store the address of this operand in? Let's imagine that this pointer should not be a pointer of any specific type, but it must be almost always assigned to another type of pointer, therefore, it should be able to easily convert data types with other class pointers. in fact, the C language provides such a pointer: void pointer. The features of this pointer are as follows:
The void pointer is not associated with any data type. It can be automatically converted to other types without force type conversion.
The "*" operator cannot be used for the void pointer, because the void pointer does not know the memory units occupied by the data it refers.
The ++ operation of the void pointer adds 1 to its address value.
Since you cannot cancel referencing a void pointer (2nd entries), it can only be used for conversion from other types of pointers. in fact, this is always used to complete general data type programming. this process can be expressed:
Dedicated code-> specific type pointer-> void pointer-> common code-> void pointer-> selected type pointer-> dedicated code.
It can be seen that the void pointer is the link between common code and dedicated code. For code that requires generic processing, the information transmitted between the void pointer and other code must be passed through the void pointer, therefore, the interface must be void pointer type.
Implementation of the value assignment function
Let's go back to the previous general data type assignment function, and now we can fully implement it! The idea is to pass the pointer of two operands to the function and specify the number of units in the memory space occupied by the data, then, copy the content of the source operand memory space to the target operand memory space in the function to complete the assignment. then, the function prototype should be void assign (void * pvdes, void * pvsrc, sizet size). The parameter meaning is:
Pvdes: Target operand pointer
Pvsrc: Source operand pointer
Size: Data byte width
An example of a function is:
Int ia = 2;
Int ib;
Assign (& ib, & ia, sizeof (int) double da = 2.0;
Double db;
Assign (& db, & da, sizeof (double ));
In this example, the assign function is used to assign values to int and double variables. Although the variable types are different, the assign method is the same, therefore, this function has a general data type.
The above assignment operation is essentially memory replication. For this operation, the C language provides specialized functions:
Void * memcpy (void * dest, const void * src, sizet n); we can see that the assign () and memcpy () interfaces are basically the same. Therefore, in the following content, we will directly use memcpy () to complete the assignment operation.
General data stack
Based on the above content, it is not far from the real implementation of a general data type stack, because the most critical part is the implementation of variable assignment, and this problem has been solved.
Stack implementation idea: during stack initialization, specify the data width of the elements in the stack and save the value in a variable in the stack; when using push to save elements to the stack, the above value assignment function is used for data transmission. The pop operation and push implementation mechanism are the same. The stack uses a single-chain table to save data.