Что значит void в C, C ++ и C #?


170

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


2
Этот вопрос состоит из 3 языков ... этот старый вопрос должен быть разделен на 3 разных вопроса.
Stargateur

Ответы:


225

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

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

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

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

  3. Указатель общих данных: void* data - «данные» - это указатель на данные неизвестного типа, и на них нельзя ссылаться

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


7
void в списке аргументов является необязательным в C ++, см. stackoverflow.com/questions/416345/…
Daniel Earwicker,

1
Я бы использовал «без типа», а не «без размера»
Kjetil Joergensen

@Earwicker и kjetijor, оба хороших момента, о которых я спорил, но мой бессонный ум нуждался в помощи;) Спасибо.
Джеральд

9
Не согласен, но дополнительное использование void в трюке «бросить в пустоту» для подавления предупреждений для неиспользуемых значений. Это немного натянуто, поскольку на самом деле это не соответствует тому, как компилятор интерпретирует вещи, но вы можете интерпретировать это как «я использую это значение, чтобы ничего не делать».
Стив Джессоп

22
В C ++ void в списке аргументов не является обязательным. Однако в C это НЕ является обязательным: foo () означает, что он принимает любое количество параметров любого типа, тогда как foo (void) означает, что он принимает нулевые параметры.
Адам Розенфилд

33

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

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

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

  • T t = void;- инициализирующее значение отсутствует

4
Что делает (void)p? Я не совсем понял, что вы имели в виду под «использованием значения отсутствует».
Yashas

@Yashas Если кто-то также смущен этим (void) var;утверждением, я нашел подробные ответы на stackoverflow.com/q/21045615 .
Arnie97

14

Есть два способа использования 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

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


4

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

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

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


3

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

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

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

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

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

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

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

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


2

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

public void DoSomeWork()
{
//some work
}

4
Большинство людей не понимают , что недействительные карты к System.Void корпусного msdn.microsoft.com/en-us/library/system.void.aspx
RichardOD

2

Три варианта использования для 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

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

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

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


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

Исправление к моему последнему комментарию - я хотел сказать последний абзац (не предложение).
Марк Эмблинг

1

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

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


0

Пустота используется только в сигнатурах метода. Для возвращаемых типов это означает, что метод не будет ничего возвращать вызывающему коду. Для параметров это означает, что в метод не передаются параметры

например

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

В C # мы можем опустить void для параметров и написать следующий код как:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

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


0

Void - это неполный тип, который по определению не может быть lvalue. Это означает, что ему нельзя присвоить значение.

Так что это также не может иметь никакой ценности.


-1

void означает, что вы не будете возвращать никакого значения из функции или метода



-1

Пустота является эквивалентом Sub Visual Basic.


Только в качестве типа возврата. Я могу вспомнить еще три варианта использования void: аргументы void (функция ничего не берет), указатели void (тип указателя не указан) и приведение типа void (значение отбрасывания).
c4757p
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.