Что значит void в C, C ++ и C #? - PullRequest
162 голосов
/ 25 июня 2009

Хотите узнать, откуда взялся термин " void ", и почему он называется void. Цель этого вопроса - помочь кому-то, у кого нет опыта работы с C, и он вдруг смотрит на кодовую базу на основе C.

Ответы [ 15 ]

215 голосов
/ 25 июня 2009

В основном это означает "ничего" или "нет типа"

Существует 3 основных способа использования void:

  1. Аргумент функции: int myFunc(void) - функция не берет ничего.

  2. Возвращаемое значение функции: void myFunc(int) - функция ничего не возвращает

  3. Общий указатель данных: void* data - 'data' - указатель на данные неизвестного типа, и на него нельзя разыменовать

Примечание: void в аргументе функции является необязательным в C ++, поэтому int myFunc() точно такой же, как int myFunc(void), и полностью отсутствует в C #. Это всегда требуется для возвращаемого значения.

29 голосов
/ 25 июня 2009

Я всегда понимал, что отсутствует . Вот четыре случая на языке C, которые соответствуют этому использованию: отсутствует

  • R f(void) - параметры функции отсутствуют
  • void f(P) - Возвращаемое значение отсутствует
  • void *p - Тип того, на что указывают, отсутствует
  • (void) p - Использование значения отсутствует

Другие потомки Си используют его для других вещей. Язык программирования D использует его для случаев, когда инициализатор отсутствует

  • T t = void; - начальное значение отсутствует
13 голосов
/ 25 июня 2009

Существует два способа использования void:

void foo(void);

или

void *bar(void*);

Первый означает, что аргумент не передается или аргумент не возвращается.

Второй говорит компилятору, что с данными не связан тип, что означает, что вы не сможете использовать данные, на которые указывают, пока они не будут преобразованы в известный тип.

Например, выvoid* будет часто использоваться, когда у вас есть интерфейс, который вызывает функцию, параметры которой не могут быть известны заранее.

Например, в ядре Linux при отложении работы вы настраиваете функцию набудет запущен позднее, указав ему указатель на функцию, которую нужно запустить, и указатель на данные, которые будут переданы функции:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

Затем поток ядра просматривает список отложенной работы.и когда он добирается до этого узла, он эффективно выполняет:

bar(somedata);

Тогда в баре у вас есть:

void bar(void* mydata) {
    int *data = mydata;
    /* do something with data */;
}
13 голосов
/ 25 июня 2009

Это означает «нет значения». Вы используете void, чтобы указать, что функция не возвращает значение или что она не имеет параметров или того и другого. В значительной степени согласуется с типичным использованием слова void в английском.

4 голосов
/ 25 июня 2009

Указывает на отсутствие возвращаемого значения в функции.

Некоторые языки имеют два вида подпрограмм: процедуры и функции. Процедуры - это просто последовательность операций, тогда как функция - это последовательность операций, которые возвращают результат.

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

3 голосов
/ 28 июня 2009

Думайте о пустоте как о "пустой структуре". Позвольте мне объяснить.

Каждая функция принимает последовательность параметров, где каждый параметр имеет тип. Фактически, мы могли бы упаковать параметры в структуру со слотами структуры, соответствующими параметрам. Это позволяет каждой функции иметь ровно один аргумент. Точно так же функции выдают результат, который имеет тип. Это может быть логическое значение, или это может быть float, или это может быть структура, содержащая произвольный набор других типизированных значений. Если нам нужен язык с несколькими возвращаемыми значениями, просто настаивать, чтобы они были упакованы в структуру. Фактически, мы всегда можем настаивать на том, чтобы функция возвращала структуру. Теперь каждая функция принимает ровно один аргумент и выдает ровно одно значение.

Теперь, что происходит, когда мне нужна функция, которая выдает "нет" значения? Хорошо, рассмотрим, что я получу, когда сформирую структуру с 3 слотами: содержит 3 значения. Когда у меня есть 2 слота, он содержит два значения. Когда это имеет один слот, одно значение. И когда у него ноль слотов, он держит ... э-э, нулевые значения, или «нет» значения. Таким образом, я могу думать о функции, возвращающей пустоту как возвращение структуры, не содержащей значений. Вы даже можете решить, что "пустота" это просто синоним для типа, представленного пустой структурой, а не ключевое слово в языке (может быть, это просто предопределенный тип:)

Точно так же я могу думать о функции, не требующей значений, как о принятии пустой структуры, например, "void".

Я даже могу реализовать свой язык программирования таким образом. Передача пустого значения занимает нулевые байты, поэтому передача пустых значений является лишь частным случаем передачи другие значения произвольного размера. Это облегчает обработку компилятором «пустой» результат или аргумент. Вы, вероятно, хотите функцию языка это может отбросить результат функции; в C, если вы называете не пустым результатом функция foo в следующем утверждении: Foo (...); компилятор знает, что foo выдает результат, и просто игнорирует его. Если void является значением, это работает отлично, и теперь "процедуры" (которые просто прилагательное для функции с пустым результатом) просто тривиально случаи общих функций.

Void * немного смешнее. Я не думаю, что дизайнеры C думали о пустоте в вышеуказанным способом; они просто создали ключевое слово. Это ключевое слово было доступно, когда кто-то нужна точка на произвольный тип, поэтому void * как идиома в C. Это на самом деле работает довольно хорошо, если вы интерпретируете пустоту как пустую структуру. Указатель void * - это адрес места, где эта пустая структура имеет был поставлен

Преобразование из void * в T * для других типов T также работает с этой точки зрения. Приведения указателей представляют собой полный чит, который работает на большинстве распространенных архитектур, чтобы использовать тот факт, что если составной тип T имеет элемент с подтипом S, физически помещенный в начале T в его макете хранения, то приведение S * к T * наоборот, использование одного и того же физического адреса машины имеет тенденцию работать, так как большинство указателей машины имеют одно представление. Замена типа S на тип void дает точно такой же эффект, и, таким образом, приведение к / от void * работает.

Язык программирования PARLANSE реализует вышеприведенные идеи довольно близко. Мы дурачились в его дизайне и не обращали пристального внимания на «пустоту» в качестве возврата введите и, следовательно, есть ключевые слова языка для процедуры. В основном это просто изменение синтаксиса, но это одна из вещей, вы не можете обойтись, как только вы получите большой рабочий код на языке.

2 голосов
/ 25 июня 2009

Если вы объясняете концепцию новичку, может быть полезно использовать аналогию. Использование void во всех этих случаях аналогично по смыслу странице в книге, в которой есть следующие слова: «Эта страница оставлена ​​намеренно пустой». Он должен различать для компилятора что-то, что должно быть помечено как ошибка, и тип, который намеренно следует оставить пустым, потому что это поведение, которое вы хотите.

Он всегда появляется в коде, где обычно ожидается появление типа, такого как тип возврата или тип указателя. Вот почему в C # void отображается на фактический тип CLR, System.Void, потому что это сам по себе тип.

Некоторые языки программирования никогда не разрабатывали концепцию пустоты, точно так же, как некоторые человеческие культуры никогда не изобретали концепцию числа ноль. Пустота представляет собой тот же прогресс в языке программирования, что и концепция нуля для человеческого языка.

2 голосов
/ 25 июня 2009

Три варианта использования для void:

  1. Подписи функций. void foo(int bar) не возвращает значение. int bar(void) не принимает никаких параметров, но это обычно выражается пустым списком аргументов: int bar(). Использование ключевого слова void здесь соответствует его значению на английском языке.

  2. Общий указатель верхнего типа void *, который указывает на неопределенные данные и не может быть разыменован. Здесь значение void отличается от других значений void: универсальный тип против отсутствия типа.

  3. В приведениях, таких как (void) new Foo(this), чтобы показать, что возвращаемое значение намеренно выбрасывается Здесь использование ключевого слова также соответствует его значению на английском языке.

Случаи 1 и 2 уже были охвачены @Gerald, но случай 3 еще не рассматривался.

2 голосов
/ 25 июня 2009

В c # вы бы использовали ключевое слово void, чтобы указать, что метод не возвращает значение:

public void DoSomeWork()
{
//some work
}
1 голос
/ 28 декабря 2015

Это означает «нет значения». Вы используете void, чтобы указать, что функция не возвращает значение или что у нее нет параметров или обоих параметров. Это очень согласуется с типичным использованием слова void в английском языке.

Пусто не следует путать с нулем. Ноль означает, что для переменной, адрес которой находится в стеке, значение в куче для этого адреса пусто.

...