Explicación detallada y aplicación de void * en lenguaje C

Void se interpreta como un sustantivo en inglés como "vacío; espacio; hueco"; y en lenguaje C, void se traduce como "sin tipo", y el vacío correspondiente * es "puntero sin tipo". Void parece tener solo la función de "comentar" y restringir el programa. Por supuesto, el "comentario" aquí no es para proporcionar comentarios para nosotros, sino para proporcionar un supuesto comentario para el compilador.

La dirección de este artículo: http://www.cnblogs.com/archimedes/p/c-void-point.html, indique la dirección de origen para la reimpresión.

El papel del vacío:
1. La limitación de la función de retorno, esta situación es más común para nosotros.

2. La limitación de los parámetros de función, esta situación también es relativamente común.

En general, estas dos situaciones son comunes:

Cuando la función no necesita devolver un valor, debe calificarse con void, que es lo que llamamos el primer caso. Por ejemplo: void func (int a, char * b).

Cuando la función no puede aceptar parámetros, debe usar la calificación void, que es lo que llamamos el segundo caso. Por ejemplo: int func (void).

Reglas para el uso de punteros nulos:
1. Un puntero nulo puede apuntar a cualquier tipo de dato, es decir, se puede utilizar cualquier tipo de puntero para asignar un valor a un puntero nulo. P.ej:

  int *a;

  void *p;

  p=a;

Si desea asignar un puntero vacío p a punteros de otros tipos, debe lanzar, en este caso: a = (int *) p. En la asignación de memoria, podemos ver el uso de punteros void: el puntero devuelto por la función de asignación de memoria malloc es void *. Cuando el usuario usa este puntero, debe realizar una conversión de tipo forzada, es decir, indicar explícitamente la memoria apuntada El tipo de datos que se almacenan en (int ) malloc (1024) significa que es obligatorio almacenar los datos en la memoria a la que apunta el puntero void devuelto por malloc .

2. En el estándar ANSI C, algunas operaciones aritméticas en punteros void como p ++ o p + = 1 no están permitidas, porque dado que void no tiene tipo, no sabemos cuántos bytes operar en cada operación aritmética, como char The type opera en sizeof (char) bytes, mientras que int tiene que operar en sizeof (int) bytes. En GNU, está permitido, porque de forma predeterminada, GNU considera que void * es lo mismo que char *. Dado que es cierto, por supuesto, se pueden realizar algunas operaciones aritméticas, donde sizeof (* p) == sizeof (char).

Void casi solo tiene la función de "comentar" y restringir el programa, porque nadie ha definido nunca una variable void, intentemos definir:

anular un;

Cuando se compila esta línea de declaración, se producirá un error que provocará un "uso ilegal del tipo 'vacío'". Incluso si la compilación de void a no comete un error, no tiene un significado práctico.

Como todos sabemos, si los punteros p1 y p2 son del mismo tipo, entonces podemos asignar valores directamente entre p1 y p2; si p1 y p2 apuntan a diferentes tipos de datos, debemos usar el operador de conversión para convertir el puntero tipo en el lado derecho del operador de asignación Es el tipo del puntero izquierdo.

 float *p1;
 int *p2;
 p1 = p2;

// La declaración p1 = p2 compilará el error,
// indicará "'=': no ​​se puede convertir de'int * 'a'float *'", debe cambiarse a:
p1 = (float *) p2;
y void * es diferente, se le puede asignar directamente cualquier tipo de puntero, sin coacción

void *p1;
int *p2;
p1 = p2;

Pero esto no significa que void * también pueda asignarse a punteros de otros tipos sin conversión. Porque "no type" puede contener "typed" y "typed" no puede contener "no type".

Tenga cuidado con los tipos de puntero vacíos:

De acuerdo con el estándar ANSI (American National Standards Institute), no puede realizar operaciones aritméticas en punteros nulos, es decir, las siguientes operaciones son ilegales:

void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误

// La razón por la que el estándar ANSI reconoce esto es porque insiste: el puntero para operaciones aritméticas debe estar seguro de conocer el tamaño del tipo de datos al que apunta.
//P.ej:

int *pint;
pint++; //ANSI:正确

El resultado de pint ++ es aumentar el tamaño de (int).
Pero GNU no lo cree así, especifica que la operación aritmética de void * es consistente con char *. Por lo tanto, las siguientes declaraciones son correctas en el compilador GNU:

pvoid++; //GNU:正确
pvoid += 1; //GNU:正确

El resultado de ejecución de pvoid ++ es que ha aumentado en 1.
En el diseño del programa real, para cumplir con el estándar ANSI y mejorar la portabilidad del programa, podemos escribir el código para lograr la misma función de la siguiente manera:

void * pvoid;
((char *)pvoid)++; //ANSI:错误;GNU:正确
(char *)pvoid += 1; //ANSI:错误;GNU:正确

Existen algunas diferencias entre GNU y ANSI. En términos generales, GNU es más "abierto" que ANSI y proporciona más soporte de sintaxis. Pero cuando estamos diseñando en la vida real, debemos seguir los estándares ANSI tanto como sea posible. Si los parámetros de la función pueden ser punteros de cualquier tipo, entonces los parámetros deben declararse como nulos *

Nota: El puntero void puede ser cualquier tipo de dato, lo que nos puede traer algunos beneficios en el programa, cuando la función es de tipo puntero, podemos definirla como puntero void, de modo que la función pueda aceptar cualquier tipo de puntero. Tal como:

Los prototipos de funciones de las funciones típicas de operación de memoria memcpy y memset son:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

De esta manera, cualquier tipo de puntero se puede pasar a memcpy y memset, que también refleja verdaderamente el significado de la función de operación de memoria, porque el objeto sobre el que opera es solo una parte de la memoria, independientemente del tipo de memoria (ver C implementación del lenguaje Programación genérica). Si el tipo de parámetro de memcpy y memset no es void *, sino char *, ¡eso es realmente extraño! ¡Tales memcpy y memset obviamente no son una función "pura, de diversión de bajo nivel"! La aparición de vacío es solo por una necesidad abstracta Si comprende correctamente el concepto de "clase base abstracta" en la orientación a objetos, es fácil comprender el tipo de datos vacío. Así como no podemos definir una instancia para una clase base abstracta, no podemos definir una variable void (llamémosla void a un "tipo de datos abstracto" de manera análoga).

Reimpreso de: https://www.cnblogs.com/wuyudong/p/c-void-point.html

Supongo que te gusta

Origin blog.csdn.net/weixin_42692164/article/details/113616383
Recomendado
Clasificación