¿Qué significa void en C, C ++ y C #?


170

Buscando obtener los fundamentos sobre el origen del término " vacío " y por qué se llama vacío. La intención de la pregunta es ayudar a alguien que no tiene experiencia en C y de repente está buscando una base de código basada en C.


2
Esta pregunta combina 3 idiomas ... esa pregunta heredada debe dividirse en 3 preguntas diferentes.
Stargateur

Respuestas:


225

Básicamente significa "nada" o "sin tipo"

Hay 3 formas básicas de usar el vacío:

  1. Argumento de int myFunc(void) la función : la función no toma nada.

  2. Valor de retorno de void myFunc(int) la función : la función no devuelve nada

  3. Puntero de datos genérico: void* data - 'datos' es un puntero a datos de tipo desconocido, y no puede ser desreferenciado

Nota: el voidargumento en una función es opcional en C ++, por lo que int myFunc()es exactamente el mismo que int myFunc(void), y se deja completamente en C #. Siempre se requiere para un valor de retorno.


77
nulo en la lista de argumentos es opcional en C ++, consulte stackoverflow.com/questions/416345/…
Daniel Earwicker

1

@Earwicker y kjetijor, ambos buenos puntos sobre los que debatí, pero mi mente insomne ​​necesitaba ayuda;) Gracias.
Gerald

9
No estoy en desacuerdo, pero hay un uso adicional de void en el truco "cast to void" para suprimir las advertencias de valores no utilizados. Es un poco exagerado ya que en realidad no se corresponde con la forma en que el compilador interpreta las cosas, pero puede interpretar que significa "Estoy usando este valor para no hacer nada".
Steve Jessop

22
En C ++, void en la lista de argumentos es opcional. Sin embargo, en C, NO es opcional: foo () significa que toma cualquier número de parámetros de cualquier tipo, mientras que foo (void) significa que toma cero parámetros.
Adam Rosenfield

33

Siempre lo he tomado como ausente . Aquí hay cuatro casos en el lenguaje C que coinciden con este uso de ausente

  • R f(void)- Los parámetros de la función están ausentes
  • void f(P)- El valor de retorno está ausente
  • void *p- El tipo de lo que se señala está ausente
  • (void) p- El uso del valor está ausente

Otros descendientes de C lo usan para otras cosas. El Dlenguaje de programación lo utiliza para casos en los que falta un inicializador

  • T t = void;- el valor de inicialización está ausente

44
¿Qué (void)phacer? No entendí lo que querías decir con "el uso del valor está ausente".
Yashas

@Yashas Si alguien también está confundido acerca de la (void) var;declaración, he encontrado respuestas detalladas en stackoverflow.com/q/21045615 .
Arnie97

14

Hay dos formas de usar void:

void foo(void);

o

void *bar(void*);

El primero indica que no se pasa ningún argumento o que no se devuelve ningún argumento.

El segundo le dice al compilador que no hay ningún tipo asociado con los datos de manera efectiva, lo que significa que no puede hacer uso de los datos apuntados hasta que se conviertan en un tipo conocido.

Por ejemplo, verá que se void*usa mucho cuando tiene una interfaz que llama a una función cuyos parámetros no se pueden conocer de antemano.

Por ejemplo, en el Kernel de Linux al diferir el trabajo, configurará una función para que se ejecute en un momento posterior, dándole un puntero a la función que se ejecutará y un puntero a los datos que se pasarán a la función:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

Luego, un subproceso del kernel pasa por una lista de trabajos diferidos y, cuando llega a este nodo, se ejecuta efectivamente:

bar(somedata);

Luego en el bar tienes:

void bar(void* mydata) {
    int *data = mydata;
    /* do something with data */;
}

13

Significa "sin valor". Se usa voidpara indicar que una función no devuelve un valor o que no tiene parámetros o ambos. Bastante consistente con los usos típicos de la palabra void en inglés.


4

Indica la ausencia de un valor de retorno en una función.

Algunos lenguajes tienen dos tipos de subrutinas: procedimientos y funciones. Los procedimientos son solo una secuencia de operaciones, mientras que una función es una secuencia de operaciones que devuelve un resultado.

En C y sus derivados, la diferencia entre los dos no es explícita. Todo es básicamente una función. la voidpalabra clave indica que no es una función "real", ya que no devuelve un valor.


3

Piense en el vacío como la "estructura vacía". Dejame explicar.

Cada función toma una secuencia de parámetros, donde cada parámetro tiene un tipo. De hecho, podríamos agrupar los parámetros en una estructura, con los espacios de estructura correspondientes a los parámetros. Esto hace que cada función tenga exactamente un argumento. Del mismo modo, las funciones producen un resultado, que tiene un tipo. Podría ser un booleano, o podría ser flotante, o podría ser una estructura, que contiene un conjunto arbitrario de otros valores escritos. Si queremos un lenguaje que tenga múltiples valores de retorno, es fácil insistir en que se empaqueten en una estructura. De hecho, siempre podemos insistir en que una función devuelve una estructura. Ahora cada función toma exactamente un argumento y produce exactamente un valor.

Ahora, ¿qué sucede cuando necesito una función que produce un valor "no"? Bueno, considere lo que obtengo cuando formo una estructura con 3 ranuras: contiene 3 valores. Cuando tengo 2 ranuras, tiene dos valores. Cuando tiene una ranura, un valor. Y cuando tiene cero ranuras, contiene ... uh, valores cero o "no" valor ". Entonces, puedo pensar en una función que devuelve void como una estructura que no contiene valores. Incluso puede decidir que" void " es solo un sinónimo del tipo representado por la estructura vacía, en lugar de una palabra clave en el idioma (quizás sea solo un tipo predefinido :)

Del mismo modo, puedo pensar en una función que no requiere valores como aceptar una estructura vacía, por ejemplo, "vacío".

Incluso puedo implementar mi lenguaje de programación de esta manera. Pasar un valor vacío ocupa cero bytes, por lo que pasar valores vacíos es solo un caso especial de pasar otros valores de tamaño arbitrario. Esto facilita que el compilador trate el resultado o argumento "nulo". Probablemente desee una función de idioma que pueda descartar el resultado de una función; en C, si llama a la función de resultado no nula foo en la siguiente declaración: foo (...); el compilador sabe que foo produce un resultado y simplemente lo ignora. Si void es un valor, esto funciona perfectamente y ahora los "procedimientos" (que son solo un adjetivo para una función con resultado void) son solo casos especiales triviales de funciones generales.

Void * es un poco más divertido. No creo que los diseñadores de C pensaron en vacío de la manera anterior; Acaban de crear una palabra clave. Esa palabra clave estaba disponible cuando alguien necesitaba un punto para un tipo arbitrario, por lo tanto nulo * como el modismo en C. En realidad, funciona bastante bien si interpreta nulo como una estructura vacía. Un puntero nulo * es la dirección de un lugar donde se ha colocado esa estructura vacía.

Los lanzamientos de nulo * a T * para otros tipos T, también funcionan con esta perspectiva. Los lanzamientos de punteros son un truco completo que funciona en la mayoría de las arquitecturas comunes para aprovechar el hecho de que si un tipo compuesto T tiene un elemento con el subtipo S colocado físicamente al comienzo de T en su diseño de almacenamiento, entonces lanza S * a T * y viceversa, el uso de la misma dirección de máquina física tiende a funcionar, ya que la mayoría de los punteros de máquina tienen una única representación. Reemplazar el tipo S por el tipo void produce exactamente el mismo efecto, y por lo tanto, lanzar hacia / desde void * funciona.

El lenguaje de programación PARLANSE implementa las ideas anteriores muy de cerca. Nos burlamos de su diseño y no prestamos mucha atención al "vacío" como tipo de retorno y, por lo tanto, tenemos palabras clave de lenguaje para el procedimiento. Es principalmente un simple cambio de sintaxis, pero es una de las cosas a las que no se puede acceder una vez que obtiene un código de trabajo de gran cuerpo en un idioma.



2

Tres casos de uso para vacío:

  1. Firmas de funciones. void foo(int bar)no devuelve un valor int bar(void)no toma ningún parámetro, pero esto se expresa por lo general con lista de argumentos vacía: int bar(). El uso de la palabra clave nula aquí corresponde a su significado en inglés.

  2. Puntero genérico de tipo superior void *que apunta a datos no especificados y no se puede desreferenciar. Aquí el significado de vacío es diferente de otros significados de vacío: tipo universal versus ningún tipo.

  3. En modelos como (void) new Foo(this)para significar que el valor de retorno se desecha deliberadamente. Aquí el uso de palabras clave también coincide con su significado en inglés.

Los casos 1 y 2 ya estaban cubiertos por @Gerald, pero el caso 3 aún no se ha abordado.


2

Si está explicando el concepto a un principiante, podría ser útil usar una analogía. El uso de vacío en todos estos casos es análogo al significado de una página en un libro que tiene las siguientes palabras, "Esta página se dejó en blanco intencionalmente". Es para diferenciar al compilador entre algo que debe marcarse como un error, frente a un tipo que debe dejarse en blanco intencionalmente porque ese es el comportamiento que desea.

Siempre aparece en el código donde normalmente esperaría ver aparecer un tipo, como un tipo de retorno o un tipo de puntero. Es por eso que en C #, void se asigna a un tipo CLR real, System.Void porque es un tipo en sí mismo.

Algunos lenguajes de programación nunca desarrollaron el concepto de vacío, al igual que algunas culturas humanas nunca inventaron el concepto del número cero. El vacío representa el mismo avance en un lenguaje de programación que el concepto de cero representa para el lenguaje humano.


Solo una nota con respecto a su última oración: tenga en cuenta que solo es cierto para los idiomas escritos estáticamente. Los lenguajes escritos dinámicamente no necesitan vacío ya que sus métodos simplemente no devuelven nada: el "vacío" está implícito en la falta de cualquier otra cosa que se devuelva.
Mark Embling

Corrección a mi último comentario: quise decir el último párrafo (no la oración).
Mark Embling

1

Significa "sin valor". Utiliza void para indicar que una función no devuelve un valor o que no tiene parámetros o ambos. Es muy consistente con los usos típicos de la palabra void en inglés.

El vacío no debe confundirse con nulo. Nulo significa que para la variable cuya dirección está en la pila, el valor en el montón para esa dirección está vacío.


0

Void se usa solo en firmas de métodos. Para los tipos de devolución, significa que el método no devolverá nada al código de llamada. Para los parámetros significa que no se pasan parámetros al método.

p.ej

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

En C # podemos omitir el vacío para los parámetros y podemos escribir el código anterior como:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

El vacío no debe confundirse con nulo. Nulo significa que para la variable cuya dirección está en la pila, el valor en el montón para esa dirección está vacío.


0

El vacío es un tipo incompleto que, por definición, no puede ser un valor. Eso significa que no se le puede asignar un valor.

Por lo tanto, tampoco puede contener ningún valor.



-1

Anulado significa que no se requiere ningún valor en el tipo de retorno de una función en los tres idiomas.


-1

Void es el equivalente de Sub de Visual Basic.


Solo como un tipo de retorno. Puedo pensar en tres usos más de void: argumentos nulos (la función no toma nada), punteros nulos (sin tipo de puntero especificado) y lanzamientos nulos (valor de descarte).
c4757p
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.