foo (void *) против foo (void *)

9

Говоря функционально и синтаксически, есть ли разница между функцией, прототип которой int foo(void)и int foo(void *)?

Я знаю разницу между, например, int bar(int)и int bar(int *)- один из них ищет int, а другой ищет указатель int. Ведет ли voidсебя так же?

Ник Рид
источник
Ответ на связанный вопрос: stackoverflow.com/a/1043209/434551 .
Р Саху
Что может быть интереснее, так это разница между foo(void)и foo().
Максим Егорушкин

Ответы:

10

С этого ответа на Software Engineering, void рассматривается специально в зависимости от того, как он используется. В Cи C++, voidиспользуется для указания на отсутствие типа данных, в то время void *используется для обозначения указатель , который указывает на некоторые данные / пространства в памяти , которая не имеет тип. void *не может быть разыменовано само по себе, и должно быть сначала приведено к другому типу. Это приведение не обязательно должно быть явным в C, но должно быть явным в C++. (Вот почему мы не приводим возвращаемое значение malloc void *.)


При использовании с функцией в качестве параметра voidозначает полное отсутствие каких-либо параметров и является единственным допустимым параметром. Попытка использовать void как тип переменной или включить другие аргументы приводит к ошибке компилятора:

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

Аналогичным образом невозможно объявить переменную с типом 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;

voidкак возвращаемое значение для функции указывает, что данные не будут возвращены. Поскольку невозможно объявить переменную типа void, невозможно поймать возвращаемое значение voidфункции, даже с указателем 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);
    ^ ~~~~~~

Несовершенство void *- это другой случай. Пустой указатель указывает указатель на местоположение в памяти, но не указывает тип данных в этом указателе. (Это используется для достижения полиморфизма в C , например, с помощью функции qsort () .) Однако эти указатели могут быть сложны в использовании, поскольку очень легко случайно привести их к неправильному типу. Приведенный ниже код не будет выдавать никаких ошибок компилятора C, но приведет к неопределенному поведению:

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

Следующий код, однако, совершенно легален; приведение к пустому указателю и обратно никогда не изменяет его значение.

#include <stdio.h>

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

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

47.200000

Как параметр функции void *указывает, что тип данных в указателе, который вы передаете, неизвестен, и вы, программист, должны правильно обрабатывать все, что находится в этом месте памяти. В качестве возвращаемого значения void *указывает, что тип возвращаемых данных неизвестен или не имеет типов и должен обрабатываться программой.

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 в прототипе функции означает «нет данных» и указывает на отсутствие возвращаемого значения или параметров, void *в прототипе функции означает «данные в указателе, которому дана эта функция, не имеют известного типа» и указывают параметр или возвращаемое значение чей указатель должен быть приведен к другому типу, прежде чем данные в указателе могут быть использованы.

Ник Рид
источник
void * ... must be cast to another type first, but may be done so without an explicit cast.Не верно в C ++. В C ++ форма преобразования void*должна быть явной. PS вызов явного приведения является избыточным, поскольку приведение по определению является явным преобразованием.
eerorika
Обновлено, чтобы отразить различия в C / C ++, спасибо, что сообщили мне!
Ник Рид
4

foo(void) - функция без параметров

foo(void *)- функция с одним void *параметром

Что такое void *? Это просто указатель на данные без определенного типа. Может быть приведен к любому другому типу указателя.

unsigned add(void *arr)
{
   unsigned *uarr = arr;
   return uarr[0] + uarr[1];
}
P__J__
источник
Основной ответ, поэтому он самый лучший. Я бы просто рассказал, как это исключение во (type) vs. (type *)вселенной пар, потому что void на самом деле не тип.
Роберто Кабони
2

Говоря функционально и синтаксически, есть ли разница между функцией, прототип которой - int foo (void) и int foo (void *)?

Есть разница:

int foo(void) объявляет функцию, которая не принимает аргументов.

int foo(void *)объявляет функцию, которая принимает один аргумент типа void*.

В C ++ int foo(void)это эквивалентно int foo().

eerorika
источник