La programación genérica te permite escribir algoritmos completamente generalizados y reutilizables, cuya eficiencia es la misma que la de los algoritmos diseñados para un tipo de datos específico. En C, se puede lograr dicha programación genérica mediante algunos métodos. Aquí se presenta un método: mediante punteros sin tipo.void*。

Vea la siguiente función swap que intercambia el contenido de dos elementos, tomando el tipo int como ejemplo:

void swap(int* i1,int* i2){  
         int temp;  
         temp = *i1;  
         *i1 = *i2;  
         *i2 = temp;  
}  

Cuando quieras intercambiar dos valores de tipo char, tienes que reescribir una función cuyo tipo de parámetro sea char. ¿No se podría usar un puntero sin tipo como parámetro? Vea el siguiente cambio:

void swap(void *vp1,void *vp2){  
       void temp = *vp1;  
       *vp1 = *vp2;  
       *vp2 = temp;  
}  

Este código es incorrecto y no pasará la compilación. En primer lugar, una variable no puede declararse comovoidsin tipo. Y como no sabes de qué tipo son los argumentos que se pasan al llamar a esta función, no puedes determinar una declaración de tipo. Además, no se puede*usar * en un puntero sin tipo, porque el sistema no tiene información sobre el tamaño del objeto al que apunta dicha dirección. En la fase de compilación, el compilador no puede saber el tipo de los parámetros que se pasan a esta función. Para implementar una función genérica aquí, es necesario pasar en el lugar de la llamada el tamaño size del espacio de direcciones del objeto que se va a intercambiar, y utilizar la función memcpy() definida en el archivo de cabecera string.h para implementarlo. El cambio es el siguiente:

void swap(void *vp1,void *vp2,int size){  
      char buffer[size];//注意此处gcc编译器是允许这样声明的
      memcpy(buffer,vp1,size);  
      memcpy(vp1,vp2,size);  
      memcpy(vp2,buffer,size);  
}  

Al llamar a esta función, se puede invocar de la siguiente manera (también es aplicable a otros tipos de x, y):

int x = 27,y = 2;  
swap(&x,&y,sizeof(int));

A continuación veamos una función con otra funcionalidad:

int lsearch(int key,int array[],int size){
      for(int i = 0;i < size; ++i)
                  if(array[i] == key)
                           return i;
     return -1;
}

Esta función busca el elemento key en el array array; si lo encuentra, devuelve su índice; si no, devuelve -1.

De la misma manera, también se pueden implementar funciones genéricas:

void* lsearch(void* key, void *base, int n, int elemSize){
    for(int i = 0;i < n; ++i){
        void *elemAddr = (char *)base+i*elemSize;
        if(memcmp(key, elemAddr, elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

La tercera línea del código: convertir a la fuerza la dirección inicial del array en un puntero al tipo char, aprovechando la propiedad de que el tipo char tiene un tamaño de 1 byte, para que elemAddr apunte a la dirección inicial del elemento i-1 de este array "genérico". Como se dijo antes, en este momento no sabes qué tipo de datos has pasado, y el sistema no puede determinar cuánto mide un elemento de este array ni cuántos bytes se necesitan para saltar al siguiente elemento. Por lo tanto, al convertir a la fuerza a un puntero a char, y sumarle el producto del tamaño del elemento pasado como parámetro y el contador acumulado i, es decir, la dirección de desplazamiento, se obtiene la dirección inicial del elemento i-1 del array. De esta manera, sin importar a qué tipo apunten los punteros pasados como parámetros, se puede obtener un puntero que apunte al elemento correcto, logrando así la programación genérica.

El prototipo de la función memcmp() es: int memcmp(void *dest,const void *src,int n); compara el contenido de dos espacios de direcciones de longitud n cuyas direcciones iniciales son dest y src respectivamente.

Esta función busca el elemento key en el array base; si lo encuentra, devuelve su dirección; si no, devuelve NULL.

Si se utilizan punteros a función, se puede lograr la genericidad de su comportamiento:

void *lsearch(void *key,void *base,int n,int elemSize,int(*cmpfn)(void*,void*,int)){
    for(int i = 0;i < n; ++i){
        void *elemAddr = (char *)base+i*elemSize;
        if(cmpfn(key,elemAddr,elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

Defina además una función que se va a llamar:

int intCmp(void* elem1,void* elem2){
        int* ip1 = elem1;
        int* ip2 = elem2;
        return *ip1-*ip2;
}

Vea la siguiente llamada:

int array[] = {1,2,3,4,5,6};
int size = 6;
int number = 3;
int *found = lsearch(&number,array,size,sizeof(int),intCmp);
if(found == NULL)
         printf("NO\n");
else
         printf("YES\n");

El lenguaje C también puede implementar cierta programación genérica, pero esto no es seguro; el sistema solo realiza una verificación limitada. Al programar, hay que tener mucho cuidado.

Dirección original: https://www.cnblogs.com/wuyudong/p/c-general-function1.html