foo (nichtig) vs foo (nichtig *)

9

Gibt es funktional und syntaktisch einen Unterschied zwischen einer Funktion, deren Prototyp ist int foo(void)und int foo(void *)?

Ich kenne den Unterschied zwischen zum Beispiel int bar(int)und int bar(int *)- einer von ihnen sucht nach einem int und der andere sucht nach einem int-Zeiger. Hat voidverhalten sich genauso?

Nick Reed
quelle
Eine Antwort auf eine verwandte Frage: stackoverflow.com/a/1043209/434551 .
R Sahu
Interessanter ist vielleicht der Unterschied zwischen foo(void)und foo().
Maxim Egorushkin

Antworten:

10

Ab dieser Antwort auf Software Engineering void wird je nach Verwendungszweck besonders behandelt. In Cund C++, voidwird verwendet , um anzuzeigen , eine Abwesenheit von einem Datentyp, während die void *verwendet wird , um anzuzeigen , einen Zeiger, der Punkte auf bestimmte Daten / Platz im Speicher , die nicht einen Typen besitzen. void *kann nicht alleine dereferenziert werden und muss zuerst in einen anderen Typ umgewandelt werden. Diese Besetzung muss nicht explizit in sein C, sondern muss explizit in sein C++. (Aus diesem Grund geben wir den Rückgabewert von malloc nicht aus void *.)


Bei Verwendung mit einer Funktion als Parameter voidbedeutet dies , dass keine Parameter vorhanden sind, und ist der einzige zulässige Parameter. Der Versuch, void wie einen Variablentyp zu verwenden oder andere Argumente einzuschließen, führt zu einem Compilerfehler:

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 ist ebenfalls unmöglich, eine Variable mit dem folgenden Typ zu deklarieren 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;

voidEin Rückgabewert für eine Funktion gibt an, dass keine Daten zurückgegeben werden. Da es unmöglich ist, eine Variable vom Typ zu deklarieren void, ist es unmöglich, den Rückgabewert einer voidFunktion zu erfassen , selbst mit einem ungültigen Zeiger.

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

Das Typlose void *ist ein anderer Fall. Ein ungültiger Zeiger zeigt einen Zeiger auf eine Stelle im Speicher an, zeigt jedoch nicht den Datentyp an diesem Zeiger an. (Dies wird verwendet, um Polymorphismus in C zu erzielen , z. B. mit der Funktion qsort () .) Die Verwendung dieser Zeiger kann jedoch schwierig sein, da es sehr einfach ist, sie versehentlich in den falschen Typ umzuwandeln. Der folgende Code wirft keine Compilerfehler ein C, führt jedoch zu undefiniertem Verhalten:

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

Der folgende Code ist jedoch vollkommen legal. Das Umwandeln von und zu einem leeren Zeiger ändert niemals den Wert, den er enthält.

#include <stdio.h>

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

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

47.200000

Gibt als Funktionsparameter an, void *dass der Typ der Daten an dem Zeiger, den Sie übergeben, nicht bekannt ist und es an Ihnen, dem Programmierer, liegt, alles, was sich an diesem Speicherort befindet, richtig zu behandeln. Gibt als Rückgabewert an, void *dass der Typ der zurückgegebenen Daten nicht bekannt oder typenlos ist und vom Programm verarbeitet werden muss.

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 in einem Funktionsprototyp bedeutet "keine Daten" und zeigt keinen Rückgabewert oder keine Parameter an, void *in einem Funktionsprototyp bedeutet "die Daten am Zeiger, den diese Funktion erhält, haben keinen bekannten Typ" und gibt einen Parameter oder Rückgabewert an deren Zeiger muss in einen anderen Typ umgewandelt werden, bevor die Daten am Zeiger verwendet werden können.

Nick Reed
quelle
void * ... must be cast to another type first, but may be done so without an explicit cast.Nicht wahr in C ++. In C ++ muss das Konvertierungsformular void*explizit sein. PS, das eine explizite Umwandlung aufruft, ist redundant, da die Umwandlung per Definition eine explizite Konvertierung ist.
Eerorika
Aktualisiert, um C / C ++ - Unterschiede widerzuspiegeln. Vielen Dank, dass Sie mich informiert haben!
Nick Reed
4

foo(void) - Funktion ohne Parameter

foo(void *)- Funktion mit einem void *Parameter

Was ist void *? Es ist nur der Zeiger auf die Daten ohne angegebenen Typ. Es kann in jeden anderen Zeigertyp umgewandelt werden

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
P__J__
quelle
Wesentliche Antwort, also die beste. Ich würde nur sagen, dass dies eine Ausnahme im (type) vs. (type *)Universum der Paare ist, weil void eigentlich kein Typ ist.
Roberto Caboni
2

Gibt es funktional und syntaktisch einen Unterschied zwischen einer Funktion, deren Prototyp int foo (void) und int foo (void *) ist?

Da ist ein Unterschied:

int foo(void) deklariert eine Funktion, die keine Argumente akzeptiert.

int foo(void *)deklariert eine Funktion, die ein einzelnes Argument vom Typ akzeptiert void*.

In C ++ int foo(void)ist gleichbedeutend mit int foo().

Eerorika
quelle