Ищите основы того, откуда взялся термин « пустота », и почему он называется пустым. Цель этого вопроса - помочь кому-то, у кого нет опыта работы с C, и он вдруг смотрит на кодовую базу на основе C.
Ищите основы того, откуда взялся термин « пустота », и почему он называется пустым. Цель этого вопроса - помочь кому-то, у кого нет опыта работы с C, и он вдруг смотрит на кодовую базу на основе C.
Ответы:
В основном это означает «ничего» или «нет типа»
Существует 3 основных способа использования void:
Аргумент функции: int myFunc(void)
- функция не берет ничего.
Возвращаемое значение функции: void myFunc(int)
- функция ничего не возвращает
Указатель общих данных: void* data
- «данные» - это указатель на данные неизвестного типа, и на них нельзя ссылаться
Примечание: void
аргумент в функции является необязательным в C ++, поэтому int myFunc()
он точно такой же, как int myFunc(void)
и полностью исключен в C #. Это всегда требуется для возвращаемого значения.
Я всегда считал это отсутствующим . Вот четыре случая на языке C, которые соответствуют этому отсутствию
R f(void)
- Параметры функции отсутствуютvoid f(P)
- Возвращаемое значение отсутствуетvoid *p
- Тип того, на что указано, отсутствует(void) p
- использование значения отсутствуетДругие потомки Си используют его для других вещей. Язык D
программирования использует его для случаев, когда инициализатор отсутствует
T t = void;
- инициализирующее значение отсутствует(void)p
? Я не совсем понял, что вы имели в виду под «использованием значения отсутствует».
(void) var;
утверждением, я нашел подробные ответы на stackoverflow.com/q/21045615 .
Есть два способа использования 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 */;
}
Это означает «нет значения». Вы используете, void
чтобы указать, что функция не возвращает значение или что она не имеет параметров или того и другого. В значительной степени согласуется с типичным использованием слова void в английском языке.
Это указывает на отсутствие возвращаемого значения в функции.
Некоторые языки имеют два вида подпрограмм: процедуры и функции. Процедуры - это просто последовательность операций, тогда как функция - это последовательность операций, которые возвращают результат.
В C и его производных разница между ними не является явной. Все в основном функция. void
ключевое слово указывает на то, что это не «фактический» функция, так как она не возвращает значение.
Думайте о пустоте как о «пустой структуре». Позволь мне объяснить.
Каждая функция принимает последовательность параметров, где каждый параметр имеет тип. Фактически, мы могли бы упаковать параметры в структуру, причем слоты структуры соответствуют параметрам. Это позволяет каждой функции иметь ровно один аргумент. Точно так же функции выдают результат, который имеет тип. Это может быть логическое значение, или это может быть 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» в качестве возвращаемого типа и, таким образом, имели ключевые слова для процедуры. В основном это просто простое изменение синтаксиса, но это одна из вещей, с которой вы не можете обойтись, когда получите большой рабочий код на языке.
В c # вы бы использовали ключевое слово void, чтобы указать, что метод не возвращает значение:
public void DoSomeWork()
{
//some work
}
Три варианта использования для void:
Подписи функций. void foo(int bar)
не возвращает значение. int bar(void)
не принимает никаких параметров , но это, как правило , выражается с пустым списком аргументов: int bar()
. Использование ключевого слова void здесь соответствует его значению на английском языке.
Общий указатель верхнего типа, void *
который указывает на неопределенные данные и не может быть разыменован. Здесь значение void отличается от других значений void: универсальный тип или отсутствие типа.
В приведениях, например, (void) new Foo(this)
для обозначения того, что возвращаемое значение намеренно выбрасывается. Здесь использование ключевого слова также соответствует его значению на английском языке.
Случаи 1 и 2 уже были охвачены @Gerald, но дело 3 еще не было рассмотрено.
Если вы объясняете концепцию новичку, может быть полезно использовать аналогию. Использование void во всех этих случаях аналогично по значению странице в книге, в которой есть следующие слова: «Эта страница оставлена намеренно пустой». Он должен отличать компилятор между чем-то, что должно быть помечено как ошибка, и типом, который намеренно следует оставить пустым, потому что это поведение, которое вы хотите.
Он всегда появляется в коде, где обычно ожидается появление типа, такого как тип возврата или тип указателя. Вот почему в C # void отображается на фактический тип CLR, System.Void, потому что он сам по себе является типом.
Некоторые языки программирования никогда не разрабатывали концепцию пустоты, как некоторые человеческие культуры никогда не изобретали концепцию числа ноль. Пустота представляет собой тот же прогресс в языке программирования, что и концепция нуля для человеческого языка.
Это означает «нет значения». Вы используете void, чтобы указать, что функция не возвращает значение или что у нее нет параметров или обоих параметров. Это очень согласуется с типичным использованием слова void в английском языке.
Пустота не должна быть перепутана с нулем. Null означает для переменной, адрес которой находится в стеке, значение в куче для этого адреса пусто.
Пустота используется только в сигнатурах метода. Для возвращаемых типов это означает, что метод не будет ничего возвращать вызывающему коду. Для параметров это означает, что в метод не передаются параметры
например
void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}
В C # мы можем опустить void для параметров и написать следующий код как:
void MethodThatReturnsAndTakesVoid()
{
// Method body
}
Пустота не должна быть перепутана с нулем. Null означает для переменной, адрес которой находится в стеке, значение в куче для этого адреса пусто.
void означает, что вы не будете возвращать никакого значения из функции или метода
Void означает, что значение не требуется в типе возврата от функции на всех трех языках.