void en inglés como sustantivo se interpreta como"vacío, espacio, hueco", y en el lenguaje C, void se traduce como"sin tipo", correspondientementevoid * Para"puntero sin tipo"。

void parece tener solo la función de "comentario" y de restricción del programa. Por supuesto, el "comentario" aquí no es para nosotros los humanos, sino que proporciona una especie de comentario al compilador.


La función de void

1. Limitación del valor de retorno de la función; esta situación es bastante común.

2. Limitación de los parámetros de la función; esta situación también es bastante común.

Generalmente, estas son las dos situaciones que vemos con frecuencia:

  • Cuando la función no necesita devolver un valor, debe usar la limitación void; este es el primer caso que mencionamos. Por ejemplo: void func(int a, char *b).
  • Cuando la función no permite aceptar parámetros, debe usar la limitación void; este es el segundo caso que mencionamos. Por ejemplo: int func(void).

Reglas de uso del puntero void

1. Un puntero void puede apuntar a datos de cualquier tipo, es decir, se puede asignar un puntero de cualquier tipo a un puntero void. Por ejemplo:

int *a;
void *p;
p=a;

Si se quiere asignar el puntero void p a un puntero de otro tipo, se necesita una conversión forzada de tipo; en este ejemplo:a=(int *)p. En la asignación de memoria podemos ver el uso del puntero void: el puntero devuelto por la función de asignación de memoria malloc es de tipovoid *tipo. Cuando el usuario usa este puntero, debe realizar una conversión forzada de tipo, es decir, indicar explícitamente qué tipo de datos se almacenan en la memoria a la que apunta el puntero.(int *)malloc(1024)Significa que se especifica forzosamente que en la memoria a la que apunta el puntero void* devuelto por malloc se almacenan datos de tipo int uno a uno.

2. En el estándar ANSI C, no se permiten operaciones aritméticas como p++ o p+=1 sobre punteros void, porque dado que void no tiene tipo, en cada operación aritmética no sabríamos cuántos bytes operar. Por ejemplo, el tipo char opera sobre sizeof(char) bytes, mientras que int debe operar sobre sizeof(int) bytes. En GNU sí se permite, porque por defecto GNU considera quevoid *ychar *son iguales; ya que es definido, por supuesto se pueden realizar algunas operaciones aritméticas. Aquísizeof(*p)==sizeof(char)。

void casi solo tiene la función de "comentario" y de restricción del programa, porque nadie definiría una variable void; intentemos definirla:

void a;

Esta línea de código dará un error al compilar, indicando"illegal use of type 'void'". Incluso sivoid ala compilación no diera error, tampoco tendría ningún significado práctico.

Como es bien sabido, si los punteros p1 y p2 son del mismo tipo, podemos asignarlos directamente entre sí; si p1 y p2 apuntan a diferentes tipos de datos, se debe usar el operador de conversión forzada de tipo para convertir el tipo del puntero a la derecha del operador de asignación al tipo del puntero a la izquierda.

float *p1;
int *p2;
p1 = p2;
//其中p1 = p2语句会编译出错,
//提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:
p1 = (float *)p2;

Yvoid *void, en cambio, es diferente: cualquier tipo de puntero se le puede asignar directamente, sin necesidad de conversión forzada de tipo.

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

Pero esto no significa quevoid *void también pueda asignarse a punteros de otros tipos sin conversión forzada de tipo. Porque "sin tipo" puede contener a "con tipo", mientras que "con tipo" no puede contener a "sin tipo".

Cuidado al usar el tipo de puntero void:

Según el estándar ANSI (American National Standards Institute), no se pueden realizar operaciones aritméticas sobre punteros void; es decir, las siguientes operaciones no son válidas:

void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
//ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。
//例如:
int *pint;
pint++; //ANSI:正确
El resultado de pint++ es incrementarlo en sizeof(int).

Pero GNU no lo considera así; especifica quevoid *las operaciones aritméticas de void son consistentes con las dechar *Por lo tanto, las siguientes declaraciones son correctas en el compilador GNU:

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

El resultado de ejecutar pvoid++ es que se incrementa en 1.

En la programación práctica, para cumplir con el estándar ANSI y mejorar la portabilidad del programa, podemos escribir el código que implementa la misma funcionalidad de la siguiente manera:

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

GNU y ANSI también tienen otras diferencias. En general, GNU es más "abierto" que ANSI y ofrece soporte para más sintaxis. Pero en el diseño real, debemos cumplir con el estándar ANSI tanto como sea posible. Si el parámetro de una función puede ser un puntero de cualquier tipo, entonces se debe declarar su parámetro comovoid *。

Nota:Un puntero void puede apuntar a datos de cualquier tipo, lo que puede traernos algunos beneficios en el programa. Cuando el parámetro formal de una función es de tipo puntero, podemos definirlo como puntero void, de modo que la función pueda aceptar punteros de cualquier tipo. Por ejemplo:

Ejemplos típicos son los prototipos de las funciones de operación de memoria memcpy y memset, respectivamente:

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 puede pasarse a memcpy y memset, lo que refleja verdaderamente el significado de las funciones de operación de memoria, porque el objeto sobre el que operan es simplemente una porción de memoria, sin importar de qué tipo sea esa memoria (ver Programación genérica en lenguaje C). Si los tipos de parámetros de memcpy y memset no fueranvoid *, sinochar *, ¡eso sí que sería realmente extraño! Tales memcpy y memset claramente no son funciones "puras, alejadas de los bajos intereses". La aparición de void es solo por una necesidad de abstracción. Si comprendes correctamente el concepto de "clase base abstracta" en la programación orientada a objetos, también es fácil entender el tipo de datos void. Así como no se puede definir una instancia de una clase base abstracta, tampoco podemos definir una variable void (comparemos a void con un "tipo de datos abstracto").

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