Red de conocimiento informático - Problemas con los teléfonos móviles - Uso de vacío

Uso de vacío

Las siguientes son las reglas para usar la palabra clave void:

Regla 1

Si la función no devuelve un valor, debe declararse como tipo void

En el lenguaje C, cualquier función que no especifique un tipo de valor de retorno será tratada por el compilador como si devolviera un valor entero. Pero muchos programadores piensan erróneamente que es un tipo vacío. Por ejemplo:

añadir (int a, int b)

{

devolver a b;

}

int main(int argc, char* argv[])

{

printf ("2 3 = d", agregar (2, 3));

}

El resultado de ejecutar el programa es la salida:

2 3 = 5

Esto muestra que la función sin descripción del valor de retorno es de hecho una función interna.

El Dr. Lin Rui mencionó en "Programación C/C de alta calidad": "El lenguaje C tiene controles de seguridad de tipos muy estrictos y no permite que ocurra la situación anterior (refiriéndose a funciones sin declaración de tipo). " Sin embargo, el compilador no necesariamente lo cree así. Por ejemplo, en Visual C 6.0, la función agregar anterior se compila sin errores ni advertencias y se ejecuta correctamente, por lo que no podemos confiar en que el compilador realice una verificación de tipos estricta.

Por lo tanto, para evitar confusiones, al escribir programas C/C, el tipo de cualquier función debe especificarse uno por uno. Si la función no devuelve un valor, debe declararse como tipo nulo. Esto no es sólo un requisito para una buena legibilidad del programa, sino también un requisito para la estandarización de la programación. Además, agregar una declaración de tipo nulo también puede desempeñar el papel de "autoanotación" del código. La "autoanotación" del código significa que el código puede anotarse a sí mismo.

Regla 2

Si una función no tiene parámetros, entonces sus parámetros deben declararse como nulos.

Declarar una función como esta en lenguaje C:

int function(void)

{

return 1;

}

Es ilegal realizar la siguiente llamada:

función(2);

Porque en C, el parámetro de función es nulo significa que esta función no acepta ningún parámetro.

Compilando en Turbo C 2.0:

#include "stdio.h"

fun()

{

return 1;

}

main()

{

printf("d", fun(2));

getchar();

}

Se compila correctamente y genera 1, lo que muestra que en lenguaje C, se puede pasar cualquier tipo a una función sin parámetros. parámetros, pero se producirá un error al compilar el mismo código en un compilador de C. En C, no se puede pasar ningún parámetro a una función sin parámetros y se muestra el mensaje de error "'divertido': la función no toma 1 parámetro".

Entonces, ya sea en C o C, si la función no acepta ningún parámetro, los parámetros deben especificarse como nulos.

Regla 3

Tenga cuidado al utilizar tipos de punteros nulos

Según los estándares ANSI (Instituto Nacional Estadounidense de Estándares), las operaciones aritméticas no se pueden realizar en punteros nulos, es decir, las siguientes operaciones son ilegales:

void * pvoid;

pvoid; //ANSI: error

pvoid = 1;

//La razón por la que el estándar ANSI determina esto es porque insiste en que los punteros para las operaciones de algoritmos deben conocer el tamaño del tipo de datos al que apuntan.

//Por ejemplo:

int *pint;

pint; //ANSI: correcto

El resultado de pinta es aumentar bigsizeof(int). (La prueba en VC6.0 es un múltiplo de sizeof(int))

Pero el famoso GNU (abreviatura de GNU's Not Unix) no lo cree así. Especifica que la operación del algoritmo de void * es consistente. con el de char *.

Por lo tanto, las siguientes declaraciones son correctas en el compilador GNU:

pvoid; //GNU: correcto

pvoid = 1 //GNU: correcto

p> El resultado de la ejecución de p>

pvoid es que se incrementa en 1. (La prueba en VC6.0 es un múltiplo de sizeof(int))

En la programación real, para cumplir con el estándar ANSI y mejorar la portabilidad del programa, podemos escribir la misma función como este Código:

void * pvoid;

(char *)pvoid; //ANSI: correcto; GNU: correcto

(char *)pvoid = 1 ; //ANSI: incorrecto; GNU: correcto

Hay algunas diferencias entre GNU y ANSI En términos generales, GNU es más "abierto" que ANSI y brinda soporte para más sintaxis. Pero cuando realmente diseñamos, debemos cumplir con los estándares ANSI tanto como sea posible.

Regla 4

Si el parámetro de una función puede ser un puntero de cualquier tipo, entonces su parámetro debe declararse como nulo *

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

void * memcpy(void *dest, const void *src, size_tlen

void * memset (void * buffer, int c); , size_t num) ;

De esta manera, cualquier tipo de puntero se puede pasar a memcpy y memset, lo que realmente refleja el significado de la función de operación de memoria, porque el objeto que opera es solo una parte de la memoria. , independientemente del tipo de memoria.

¡Sería realmente extraño si el tipo de parámetro de memcpy y memset no fuera void *, sino char *! ¡Tales memcpy y memset obviamente no son funciones "puras y libres de diversión de bajo nivel"!

El siguiente código se ejecuta correctamente:

//Ejemplo: memset acepta punteros de cualquier tipo

int intarray[100];

memset (intarray, 0, 100*sizeof(int)); //Borrar intarray a 0

//Ejemplo: memcpy acepta punteros de cualquier tipo

int intarray1[100], intarray2[ 100];

memcpy (intarray1, intarray2, 100*sizeof(int)); //Copiar intarray2 a intarray1

Curiosamente, las funciones memcpy y memset también devuelven void * tipo, ¡qué conocimientos tienen los escritores de las funciones de la biblioteca estándar!

Regla 5

void no puede representar una variable real

Todos los siguientes códigos intentan hacer que void represente una variable real, por lo que todos son códigos incorrectos:

void a; //Error

function(void a); //Error

void encarna una abstracción, y todas las variables en este mundo son " Allí es un tipo”.

La aparición de void es solo para una necesidad abstracta. Si comprende correctamente el concepto de "clase base abstracta" en orientación a objetos, es fácil comprender el tipo de datos void. Así como no podemos definir una instancia de una clase base abstracta, no podemos definir una variable nula (llamémosla nula un "tipo de datos abstracto" por analogía).

Resumen

El pequeño vacío contiene una rica filosofía de diseño. Como programador, nos beneficiaremos mucho al pensar en el problema a un nivel más profundo.

No importa qué tipo de puntero (void*, char*, int*, float*...) se compila en el modo de depuración, el valor inicial predeterminado es 0xCCCCCCC (determinado por el compilador, el propósito principal Es para agregar código auxiliar de depuración para detectar errores a tiempo). Cuando se compila en modo Lanzamiento, no es un valor definido.

#includelt;iostreamgt;

#include lt;memorygt;

//#include lt;stringgt;

usando el espacio de nombres estándar ;

void main()

{

void *p1;

int a = 10;

int *p2 = a;

cout lt; p1 lt;

cout lt;

p1 = p2;

cout lt; *(int*)p1 lt; //!!!!!! tipo nulo!

cout lt; (int)*p2 lt; endl;

}

/* Salida:

0xCCCCCCCC

10

10

10

*/

Asigne NULL en el mismo momento de la declaración e inmediatamente después de eliminar Establecer en NULL.

El valor inicial predeterminado del puntero en la versión de depuración es 0xCCCCCCCC, y el valor inicial en la versión de lanzamiento es 0x0000000A (VC6.0 en mi computadora). Si no hay un valor de inicialización adecuado para el puntero, se debe establecer en NULL (0).

Para una buena práctica de programación, cuando declare un puntero, inicialícelo en NULL. Si es un miembro de la clase, inicialícelo en el constructor. Cuando use eliminar en el puntero, configúrelo en NULL.

0xCCCCCCCC es solo un valor de puntero indefinido generado por VC en el estado de depuración para indicar que este puntero no se ha inicializado y no será igual a este valor en el estado de lanzamiento (a menos que sea una coincidencia). Si no hay un valor de inicialización adecuado para el puntero, se debe establecer en NULL (0).