foo (vazio) vs foo (vazio *)

9

Falando funcional e sintaticamente, existe uma diferença entre uma função cujo protótipo é int foo(void)e int foo(void *)?

Eu sei a diferença entre, por exemplo, int bar(int)e int bar(int *)- um deles está procurando um int e o outro está procurando um ponteiro int. Comporta- voidse da mesma maneira?

Nick Reed
fonte
Uma resposta para uma pergunta relacionada: stackoverflow.com/a/1043209/434551 .
R: Sahu
O que pode ser mais interessante é a diferença entre foo(void)e foo().
Maxim Egorushkin 12/11/19

Respostas:

10

A partir desta resposta em Engenharia de software, void é tratado especialmente dependendo de como é usado. In Ce C++, voidé usado para indicar uma ausência de um tipo de dados, enquanto que void *é usado para indicar um ponteiro que aponta para alguns dados / espaço na memória que não possui um tipo. void *não pode ser desreferenciado por si só e deve ser convertido para outro tipo primeiro. Essa conversão não precisa ser explícita C, mas deve ser explícita C++. (É por isso que não lançamos o valor de retorno do malloc, que é void *.)


Quando usado com uma função como parâmetro, voidsignifica uma ausência total de quaisquer parâmetros e é o único parâmetro permitido. Tentar usar o void como um tipo de variável ou incluir outros argumentos resulta em um erro do 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);
             ^

É igualmente impossível declarar uma variável com o 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 um valor de retorno para uma função indica que nenhum dado será retornado. Como é impossível declarar uma variável do tipo void, é impossível capturar o valor de retorno de uma voidfunção, mesmo com um ponteiro 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);
    ^ ~~~~~~

O tipeless void *é um caso diferente. Um ponteiro nulo indica um ponteiro para um local na memória, mas não indica o tipo de dados nesse ponteiro. (É usado para obter polimorfismo em C , como na função qsort () .) Esses indicadores podem ser difíceis de usar, no entanto, pois é muito fácil convertê-los acidentalmente no tipo errado. O código abaixo não Cgera erros de compilação , mas resulta em um comportamento 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);
}

O código a seguir, no entanto, é perfeitamente legal; converter de e para um ponteiro nulo nunca altera o valor que ele possui.

#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 função, void *indica que o tipo de dados no ponteiro em que você está passando não é conhecido e cabe a você, programador, lidar adequadamente com o que estiver naquele local de memória. Como valor de retorno, void *indica que o tipo de dado retornado não é conhecido ou não possui tipo de letra e deve ser tratado pelo programa.

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 em um protótipo de função significa "sem dados" e indica nenhum valor de retorno ou sem parâmetros, void *em um protótipo de função significa "os dados no ponteiro a que essa função é fornecida não têm um tipo conhecido" e indica um parâmetro ou valor de retorno cujo ponteiro deve ser convertido para um tipo diferente antes que os dados no ponteiro possam ser usados.

Nick Reed
fonte
void * ... must be cast to another type first, but may be done so without an explicit cast.Não é verdade em C ++. No C ++, o formulário de conversão void*deve ser explícito. O PS que chama um explícito de conversão é redundante, pois, por definição, é uma conversão explícita.
eerorika
Atualizado para refletir as diferenças de C / C ++, obrigado por me informar!
Nick Reed
4

foo(void) - função sem parâmetros

foo(void *)- função com um void *parâmetro

O que é void *? É apenas o ponteiro para os dados sem nenhum tipo especificado. Pode ser convertido para qualquer outro tipo de ponteiro

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
P__J__
fonte
Resposta essencial, por isso é a melhor. Gostaria apenas de pensar como isso é uma exceção no (type) vs. (type *)universo dos casais, porque o vazio não é realmente um tipo.
Roberto Caboni 12/11/19
2

Falando funcional e sintaticamente, existe uma diferença entre uma função cujo protótipo é int foo (vazio) e int foo (vazio *)?

Há uma diferença:

int foo(void) declara uma função que não aceita argumentos.

int foo(void *)declara uma função que aceita o argumento único do tipo void*.

Em C ++, int foo(void)é equivalente a int foo().

eerorika
fonte