foo (nulo) vs foo (nulo *)

9

Hablando funcional y sintácticamente, ¿hay alguna diferencia entre una función cuyo prototipo es int foo(void)y int foo(void *)?

Sé la diferencia entre, por ejemplo, int bar(int)y int bar(int *)- uno de ellos está buscando un int, y el otro está buscando un puntero int. ¿Se voidcomporta de la misma manera?

Nick Reed
fuente
Una respuesta a una pregunta relacionada: stackoverflow.com/a/1043209/434551 .
R Sahu
Lo que puede ser más interesante es la diferencia entre foo(void)y foo().
Maxim Egorushkin

Respuestas:

10

A partir de esta respuesta sobre Ingeniería de Software, void se trata especialmente dependiendo de cómo se use. En Cy C++, voidse usa para indicar la ausencia de un tipo de datos, mientras que void *se usa para indicar un puntero que apunta a algunos datos / espacio en la memoria que no tiene un tipo. void *no se puede desreferenciar por sí solo, y primero se debe convertir a otro tipo. Este reparto no necesita ser explícito en C, pero debe ser explícito en C++. (Es por eso que no arrojamos el valor de retorno de malloc, que es void *).


Cuando se usa con una función como parámetro, voidsignifica la ausencia total de cualquier parámetro, y es el único parámetro permitido. Intentar usar void como un tipo de variable o incluir otros argumentos da como resultado un error del compilador:

int foo(void, int);     //trying to use "void" as a parameter
int bar(void baz);      //trying to use "void" as an argument's type
main.c:1:8: error: 'void' must be the first and only parameter if specified
int foo(void, int);
       ^
main.c:2:14: error: argument may not have 'void' type
int bar(void baz);
             ^

Es igualmente imposible declarar una variable con tipo void:

int main(void) {
  void qux;         //trying to create a variable with type void
}
main.c:5:8: error: variable has incomplete type 'void'
  void qux;

voidcomo un valor de retorno para una función indica que no se devolverán datos. Como es imposible declarar una variable de tipo void, es imposible capturar el valor de retorno de una voidfunción, incluso con un puntero nulo.

void foo(int i) { return; }

int main(void) {
  void *j;
  j = foo(0);

  return 0;
}
main.c:5:5: error: assigning to 'void *' from
      incompatible type 'void'
  j = foo(0);
    ^ ~~~~~~

El sin tipo void *es un caso diferente. Un puntero nulo indica un puntero a una ubicación en la memoria, pero no indica el tipo de datos en ese puntero. (Esto se usa para lograr el polimorfismo en C , como con la función qsort ()) . Sin embargo, estos punteros pueden ser difíciles de usar, ya que es muy fácil lanzarlos accidentalmente al tipo incorrecto. El siguiente código no arrojará ningún error del compilador C, pero da como resultado un comportamiento indefinido:

#include <stdio.h>

int main(void) {
  double foo = 47.2;    //create a double
  void *bar = &foo;     //create a void pointer to that double
  char *baz = bar;      //create a char pointer from the void pointer, which
                        //is supposed to hold a double

  fprintf(stdout, "%s\n", baz);
}

El siguiente código, sin embargo, es perfectamente legal; lanzar hacia y desde un puntero vacío nunca cambia el valor que tiene.

#include <stdio.h>

int main(void) {
  double foo = 47.2;
  void *bar = &foo;
  double *baz = bar;

  fprintf(stdout, "%f\n", *baz);
}

47.200000

Como parámetro de función, void *indica que se desconoce el tipo de datos en el puntero que está pasando, y depende de usted, el programador, manejar adecuadamente lo que esté en esa ubicación de memoria. Como valor de retorno, void *indica que el tipo de datos que se devuelve no se conoce o no tiene tipo, y el programa debe manejarlo.

int quux(void *);   //a function that receives a pointer to data whose type is not known, and returns an int.
void *quuz(int);    //a function that receives an int, and returns a pointer to data whose type is not known.

tl; dr void en un prototipo de función significa "sin datos" e indica que no hay valor de retorno o ningún parámetro, void *en un prototipo de función significa que "los datos en el puntero que se da esta función no tienen un tipo conocido" e indica un parámetro o valor de retorno cuyo puntero debe convertirse a un tipo diferente antes de que se puedan utilizar los datos en el puntero.

Nick Reed
fuente
void * ... must be cast to another type first, but may be done so without an explicit cast.No es cierto en C ++. En C ++, la forma de conversión void*debe ser explícita. PS que llama a un cast explícito es redundante, ya que el cast es, por definición, una conversión explícita.
Eerorika
Actualizado para reflejar las diferencias de C / C ++, ¡gracias por hacérmelo saber!
Nick Reed
4

foo(void) - función sin parámetros

foo(void *)- función con un void *parámetro

¿Qué es void *? Es solo el puntero a los datos sin un tipo especificado. Se puede lanzar a cualquier otro tipo de puntero

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
P__J__
fuente
Respuesta esencial, por lo que es la mejor. Simplemente pensaría que esto es una excepción en el (type) vs. (type *)universo de las parejas porque el vacío no es realmente un tipo.
Roberto Caboni
2

Hablando funcional y sintácticamente, ¿hay alguna diferencia entre una función cuyo prototipo es int foo (void) e int foo (void *)?

Hay una diferencia:

int foo(void) declara una función que no acepta argumentos.

int foo(void *)declara una función que acepta un solo argumento de tipo void*.

En C ++, int foo(void)es equivalente a int foo().

eerorika
fuente