Перейти к содержимому

Void main c что это

  • автор:

Void main()

int c=4,*a,*b; a=&c; b=a+l; printf(“%p %d»,a,(int)b-(int)a); > Здесь описана и инициализирована целая переменная и два указателя на целые (int) переменные. Указатель а получает значение адреса переменной, а указатель b — значение на единицу большее. Затем печатаются адрес переменной и разность указателей, каждый из которых приведен к целому числовому типу. Казалось бы, раз b на единицу больше а, то разность между ними есть 1. При печати вы, однако, увидели бы не 1, а 2. Если заменить в описаниях int на long, то напечаталось бы 4. Дело в том, что здесь печатается разность номеров байтов, начиная с которых размещаются переменные соответствующего типа, и если переменная а размещена в байтах номер N и номер N+1 (тип int занимает два байта), то следующая переменная, указатель на которую увеличен на единицу, будет размещена в байтах N+2 и N+3. Поэтому разность указателей и составляет 2 байта, а для типа long — 4 байта. Принципиальный момент для языка С: условились считать, что имя массива (без индексов) само уже явля­ется указателем на начало этого массива, то есть если описан массив t[15], то t есть &t[0]. Тогда понятно, что *t есть значение начального элемента массива и вооб­ще *(t+i) есть не что иное, как t[i]. Более того, еще до начала компиляции программы препроцессор, о кото­ром мы вскользь упоминали раньше, производит заме­ну в тексте всех конструкций типа u[i] на конструкции *(u+i). Из этого, в частности, следует, что совершен­но чудовищная, на первый взгляд, конструкция 3[р] бу­дет совершенно безболезненно пропущена компилятором, и если вы имели в виду р[3], то все в программе будет в порядке. Тогда, если вы хотите слегка облегчить работу системы и уменьшить время обработки (но не исполне­ния) программы, пишите всегда *(р+4) вместо р[4]. В заключении параграфа приведем еще одну програм­му:

Viod main()

double m[]=,*p; for(p=m+2; p > Автор тешит себя надеждой, что читатель уже доста­точно опытен для того, чтобы понять, что эта программа выведет на экран три числа 1.4, 3.3 и 5.2.

Функции

До сих пор в наших программах мы использовали од­ну единственную «самодельную» функцию с именем main — главная. При необходимости программа может содер­жать достаточно большое количество функций, среди ко­торых, однако, присутствие функции main в консольных приложениях обязательно, поскольку именно с нее начинается выполнение любой программы. Описание и использование «самодельных» функций демонстрирует следующая программа: #includestdio.h> /*Это —— первая функция*/ double sqr(double х) return х*х; > /*Это —— вторая функция*/ double cub(double x) /*Это —— главная функция*/

Void main(void)

double у; for(y=0.; y printf(«y=%3.1lf y^2=%3.1lf y^3=%3.1lf\n», y,sqr(y),cub(y)); > Начнем с того, что не имеет отношения к описаниям функций, но впервые появилось в нашей программе. Речь идет о так называемых комментариях. Комментарием является все, что стоит между открывающей конструкцией /* и закрывающей конструкцией */. Присутствие в программе комментариев никакого влияния ни на что не оказывает. Система вообще не видит комментари­ев, и они предназначены только для человека, читающе­го программу. Зато этому человеку комментарии могут сообщить полезную информацию, как это и сделано в по­следней программе. Комментарий в одной строке мож­но организовать и по-другому: напишите конструкцию //. Все, что находится после этой конструкции до конца строки, будет комментарием. Теперь в нашей программе описана функция с име­нем sqr. Общая форма описания функции имеет вид: ТипФункции ИмяФункции(ТипАргумента1 Аргу­мент1, ТипАргумента2 Аргумент2. ) ; Если назначение функции заключается в вычисле­нии одного значения, то есть, как говорят Гуру от про­граммирования, если функция возвращает значение, то тип функции должен быть указан, и таким типом явля­ется тип возвращаемого значения. В нашей программе функция имеет тип double, стало быть, функция воз­вращает вещественное число с двойной точностью. Если тип функции не указан, то, по умолчанию, она считается целочислен­ной функцией (типа int). Если функция не возвраща­ет никакого значения, то она имеет тип void — никакой. Несмотря на отсутствие типа, слово void в описании должно присут­ствовать. Во всех наших программах функции main не возвращали значений и описывались как void. Функции, возвращающие значение, обязаны содержать в своем те­ле хотя бы одно так называемое выражение возврата: return ВозвращаемоеЗначение; Слово return и означает ВЕРНУТЬ, и после него сле­дует выражение, вычисляющее возвращаемое значение. В функциях сложной структуры, имеющих, например, несколько альтернативных путей выполнения, возможно присутствие нескольких выражений return. Нужно по­мнить, что выполнение любого из выражений возврата приводит к немедленному завершению выполнения функции, передаче возвращаемого значе­ния «наружу» и переходу к участку программы, непосредственно следую­щему за обращением к этой функции. Нетрудно видеть, что функция sqr возвращает квадрат своего аргумента. В некоторых языках программирования именно под таким именем существует именно такая функция, вычисля­ющая квадрат своего аргумента, но не «самодельная», а стандартная. Там она ничем не отличается от других стандартных функций: sin, еxр, sqrt и так далее. В С такой стандартной функции нет. Так что если вам не­пременно хочется ее иметь, то придется изготовить ее своими руками, что в последней программе и сделано. В скобках после имени функции находится список ар­гументов, разделенных запятыми. Для каждого аргумен­та указывается его тип. Даже если в списке есть не­сколько аргументов одного типа, их нельзя объединять под одним словом описания типа, как это, например, можно было делать при объявлении переменных. Такая «причуда» име­ет своей целью, в частности, уберечь программиста от злоупотребления большим числом аргументов функций. В нашем примере список аргументов состоит из одного параметра, но это только частный случай. Необходимо обратить внимание на одно крайне важное обстоятель­ство. Принимая свой аргумент, функция делает с него копию и работает уже с этой копией, а не с самим значе­нием. По этой причине, если вы в теле функции измените, как вам кажется, значение аргумента, то после выхода из функции в вызывающую ее часть программы вы с уди­влением можете обнаружить, что значение аргумента не изменилось. У такой особенности построения функций в С есть свои преимущества и свои недостатки, которые мы обсудим несколько позднее. Функция может и не иметь ни одного аргумента. Так, наприме, зачем параметры могут понадобиться функции clrscr, если ее назначение — очистка экрана? Она ведь даже не возвращает значения, не имеет типа. В случае отсутствия у функции аргументов вы можете при описании воспользоваться пустыми скобками (). Для тех, кто любит во всем порядок, как автор этих строк, посоветуем избавить себя от дискомфорта при взгляде на эти пустые скобки и писать (void). Вот мы и пол­ностью разобрались с непонятной поначалу строкой из самой первой нашей программы void main(void). Как видите, автор выполняет свои обещания. Тело функции — это запрограммированный рецепт выполнения некоторых действий. Говорить особо о по­строении тела функции нет смысла, поскольку до сих пор мы только этим и занимались. Ну, разве что еще раз на­помним, что функция, имеющая любой тип, отличный от void, должна возвращать значение с помощью выраже­ния возврата. В функции sqr тело до крайности простое. Оно даже не содержит ни одного выражения, кроме вы­ражения возврата return x*x. С последним же все ясно. Вы, конечно, догадываетесь, что такая простая ситуация скорее исключение, чем правило. Уже следующая функция в нашей программе выгля­дит чуть сложнее. Заметьте, что вторая функция cub находится в программе после функции sqr и поэтому знает, что функция sqr собой представляет. Аналогично функция main знает обе функции: и sqr и cub. Такую естествен­ную последовательность рекомендуется соблюдать в про­грамме, хотя несложные средства, демонстрируемые да­лее, позволят вам изменить этот порядок. Функция cub, как это следует из ее имени, вычисляет куб своего аргумента. Если бы выражение возврата в ней мы записали в виде return x*x*x; (что было бы не хуже представленного выше варианта), то нам было бы нечего добавить к тому, что говорилось о функции sqr. Одна­ко здесь функция возведения в куб использует функцию возведения в квадрат, то есть при своей работе функ­ция cub обращается к уже известной ей функции sqr. В свою очередь, главная функция обращается к описанным ранее функциям и успешно распечатывает таблицу ква­дратов и кубов чисел от 0 до 10 с шагом 1. Мы вполне сознаем, что такую таблицу можно было бы изготовить значительно проще. Программу следует рассматривать только как учебный пример и не более того. В приведенном примере внутри «самодельных» функ­ций sqr и cub, в отличие от функции main, нам не при­шлось описывать никаких дополнительных переменных. Однако и это скорее исключение, чем правило. Следую­щая программа демонстрирует более реалистичную си­туацию: #include

Чем отличаются функции начинающиеся с void от int в Си?

Первый вариант, по-хорошему, не должен бы компилироваться: сказано, что функция возвращает целое число, но ни одного return при этом в теле нет. main же случай особый, но его полная сигнатура по-хорошему включает возврат int (код выхода) и приём массива строк (аргументов командной строки) в виде числа элементов и указателя на нулевой из них. Но из-за исторически сложившегося разброда инструменты могут стерпеть и ряд других записей.

– user181100
2 апр 2018 в 20:54
Первый вариант не будет компилироваться.
2 апр 2018 в 20:55

void функции в Си соответствуют подпрограммам (исторически они появились до функций) в других языках. Попробуйте почитать в вике (по ссылкам). По сути разница в том, что основным назначением функции (по крайней мере к этому стоит стремиться) является возврат чистого результата, а подпрограммы — побочные эффекты

2 апр 2018 в 22:06

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

PragmaSpot

— информационная безопасность, программирование, железо.

Страницы

суббота, 31 декабря 2011 г.

Большая разница: int main() или void main()?

Функция main() обязательна для простых консольных приложений, которые мы разрабатываем в Академии в качестве множества примеров и заданий. Однако как оказалось существует существенная разница в ее употреблении. Ее могут записывать по-разному: int main() и void main().
Однако запись приведенная выше не будет корректна без записи return 0 для int main() и exit(0) для void main(). На одном из форумов встретил сообщение, что void mai() не совсем корректная запись, так как сообщает компилятору, что функция main() не возвращает никакого значения. При этом запись int main() сообщает компилятору о возвращении целочисленного значения, которое необходимо операционной системе. Это сообщение объявляет ей о том, что программа завершилась корректно. Если же это значение не возвращено, то операционная система понимает, что программа завершилась в аварийном режиме. Именно поэтому как первая запись, так и вторая требует записи операторов return 0 для int main() или для void main() – записи оператора exit(0).
Однако в языке С++ предпочтение при записи функции отдается целочисленному значению, что выглядит вот так:
int main()
return 0;
>

Алёна C++

Вообще по Стандарту C++ функция main обязана возвращать int. Насколько мне известно, так же обстоят дела и в Стандарте С. И объявление функции main как void main формально ведет к undefined behavior. Тем не менее, main очень часто объявляют как void, особенно в синтетических примерах, код при это генерируется нормально. В принципе, объявление main как void может привести к проблемам, в частности код может получиться непортируемым.
Возвращаемый результат функции main иногда становится предметом вялых религиозных споров. Лично я чаще объявляю void main.

Ссылки по теме:
Can I write «void main()»? Страуструп в своем FAQ’e рассказывает, что объявлять main как void некорректно

17 комментариев:

а зачем делать его void? всё-таки это как-никак способ сигнализировать ОС (или запускающему скрипту) об удачности или неудачности выполнения программы…

вот тут, кстати, есть разбор стандартов по этой теме: http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1044841143&id=1043284376 Ответить Удалить

а зачем делать его void?

В синтетических примерах, чтобы вообще не задумываться о возвращаемом значении и сосредоточиться на том аспекте для которого этот пример пишется. Ответить Удалить

Насколько я помню достаточно поставить return 1 или вообще ничего не возвращать. gcc же при определении void main сругнется, но скомпилит. Ответить Удалить

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

Как правило начинающие пользователи как раз учатся на этих примерах и привыкают к тому, что возвращать совершенно не обязательно. А потом они пишут программы, которые ничего не возвращают. И как в этом случае должна работать конструкция

$ newprog && echo ok

$ newprog || echo false

gcc же при определении void main сругнется, но скомпилит

$ g++-3.3 test.cpp
test.cpp:2: error: `main’ must return `int’
$ g++-3.4 test.cpp
test.cpp:2: error: `main’ must return `int’
$ g++-4.0 test.cpp
test.cpp:1: error: ‘::main’ must return ‘int’
$ g++-4.1 test.cpp
test.cpp:1: error: ‘::main’ must return ‘int’
$ g++-2.95 test.cpp

только старые версии компилятора проглотят такое Ответить Удалить

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

Все же учиться только на синтетических примерах не есть хорошо. Обычно там слишком много допущений помимо возвращаемого значения функции main.

Насколько я помню достаточно поставить return 1 или вообще ничего не возвращать.
Кстати, да. Можно написать int main и вообще ничего не возвращать. Там по умолчанию return 0 по Стандарту. Ответить Удалить

. чтобы вообще не задумываться. и сосредоточиться.

Неужели int отвлекает больше чем void? Даже букв меньше :Р,
в примере можно в конце поставить:


// Комментарий,
// в котором будет все ясно.
return 0;
Ответить Удалить

Фундаментальный вы вопрос затронули, барышня. А вообще может, да, сам видел! Ответить Удалить

Да какая разница? Тяжело написать int и return 0? Не понимаю я вас. =\

PS: Не помню себя ни разу, чтобы писал void main. Ответить Удалить

There is a reason why C assumed that every function returns int, unless specified otherwise: it’s the cheapest way to pass the value to the caller. On practically any implementation, return value is in the register. If the caller doesn’t use the return value, it doesn’t cost him anything.

Now, once you know this, you can see that the most convenient error handling mechanism in C is by using return values.

Now «main» is the function that is called by the run time library which is called by the operating system. And RTL and OS have its declaration as int main no matter how you declare main in your text.

So int main is expected to signal to the caller if the program execution was succesfull. If you don’t return anything, the caller will get the garbage, whatever was in the register at the moment of the return.

So you should really get used to this idiom. It’s very convenient too. Typically 0 means «everything ok» and other values specific error codes. Take a look at the simplest example:

f1 = fopen(
if ( !f1 ) return 1;
f2 = fopen(
if ( !f2 ) < fclose( f1); return 2; >
.
return 0;

(Off topic: Thanks for a very good blog, I often find interesting stuff here) Ответить Удалить

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *