foo (void) vs foo (void *)

9

Sur le plan fonctionnel et syntaxique, y a-t-il une différence entre une fonction dont le prototype est int foo(void)et int foo(void *)?

Je connais la différence entre, par exemple, int bar(int)et int bar(int *)- l'un d'eux cherche un int, et l'autre cherche un pointeur int. Se voidcomporte- t-il de la même manière?

Nick Reed
la source
Une réponse à une question connexe: stackoverflow.com/a/1043209/434551 .
R Sahu
Ce qui peut être plus intéressant, c'est la différence entre foo(void)et foo().
Maxim Egorushkin

Réponses:

10

De cette réponse sur le génie logiciel, void est traité spécialement en fonction de la façon dont il est utilisé. Dans Cet C++, voidest utilisé pour indiquer l'absence d'un type de données, tandis qu'il void *est utilisé pour indiquer un pointeur qui pointe vers des données / un espace en mémoire qui n'ont pas de type. void *ne peut pas être déréférencé seul et doit d'abord être converti en un autre type. Cette distribution n'a pas besoin d'être explicite dans C, mais doit être explicite dans C++. (C'est pourquoi nous ne convertissons pas la valeur de retour de malloc, qui l'est void *.)


Lorsqu'il est utilisé avec une fonction comme paramètre, voidsignifie une absence totale de tout paramètre et est le seul paramètre autorisé. Tenter d'utiliser void comme un type de variable ou d'inclure d'autres arguments entraîne une erreur de compilation:

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);
             ^

Il est également impossible de déclarer une variable de type 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;

voidcomme valeur de retour pour une fonction indique qu'aucune donnée ne sera retournée. Puisqu'il est impossible de déclarer une variable de type void, il est impossible d'attraper la valeur de retour d'une voidfonction, même avec un pointeur void.

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);
    ^ ~~~~~~

L'apatride void *est un cas différent. Un pointeur vide indique un pointeur vers un emplacement en mémoire, mais n'indique pas le type de données à ce pointeur. (Ceci est utilisé pour atteindre le polymorphisme en C , comme avec la fonction qsort () .) Ces pointeurs peuvent cependant être difficiles à utiliser, car il est très facile de les convertir accidentellement dans le mauvais type. Le code ci-dessous ne générera aucune erreur de compilation C, mais entraînera un comportement indéfini:

#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);
}

Le code suivant, cependant, est parfaitement légal; la conversion vers et depuis un pointeur vide ne modifie jamais la valeur qu'il contient.

#include <stdio.h>

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

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

47.200000

En tant que paramètre de fonction, void *indique que le type de données sur le pointeur que vous transmettez n'est pas connu, et c'est à vous, le programmeur, de gérer correctement tout ce qui se trouve à cet emplacement mémoire. En tant que valeur de retour, void *indique que le type des données renvoyées n'est pas connu ou est sans type et doit être géré par le programme.

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 dans un prototype de fonction signifie "pas de données" et indique aucune valeur de retour ou aucun paramètre, void *dans un prototype de fonction signifie "les données au pointeur que cette fonction est donnée n'ont pas de type connu" et indiquent un paramètre ou une valeur de retour dont le pointeur doit être converti en un type différent avant que les données du pointeur puissent être utilisées.

Nick Reed
la source
void * ... must be cast to another type first, but may be done so without an explicit cast.Pas vrai en C ++. En C ++, le formulaire de conversion void*doit être explicite. PS appelant un cast explicite est redondant car le cast est par définition une conversion explicite.
eerorika
Mis à jour pour refléter les différences C / C ++, merci de me le faire savoir!
Nick Reed
4

foo(void) - fonction sans paramètres

foo(void *)- fonction avec un void *paramètre

Qu'est-ce que c'est void *? Il s'agit simplement du pointeur vers les données sans type spécifié. Il peut être converti en tout autre type de pointeur

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
P J__
la source
Réponse essentielle, c'est donc la meilleure. Je voudrais juste expliquer à quel point c'est une exception dans l' (type) vs. (type *)univers des couples car le vide n'est pas vraiment un type.
Roberto Caboni
2

Sur le plan fonctionnel et syntaxique, y a-t-il une différence entre une fonction dont le prototype est int foo (void) et int foo (void *)?

Il existe une différence:

int foo(void) déclare une fonction qui n'accepte aucun argument.

int foo(void *)déclare une fonction qui accepte un seul argument de type void*.

En C ++, int foo(void)est équivalent à int foo().

eerorika
la source