Main программа для чего

Многие, увы слишком многие, программисты на вопрос «С чего начинается выполнение программы на C или C++?» издают обиженный вопль. «Дескать что за детские вопросы? Уже в старшей группе детского сада все знают. что точкой входа является функция main . » И ответ это в корне неверный. Точнее, очень часто путают понятия точки входа в программу и начала выполнения. И из-за этого периодически попадают в забавные ситуации, в которых даже отладчик не всегда может помочь. Вот и посмотрим. что же у нас в программе происходит до вызова функции main.

Надеюсь, что не открою Америку, сказав, что реальное выполнение любой программы начинается с кода загрузчика. Этот код чаще всего писан на Assembler и сильно зависит от операционной системы, компилятора, и массы других параметров. Но в любом случае — его задача провести предварительную инициализацию и настройку программы.

И только когда эта работа выполнена, загрузчик из своего кода вызывает функцию main. То есть, до вызова функции main в программе происходит много чего интересного. И если на каком-то предварительном этапе возникнет ошибка, то вызова функции main мы не получим вовсе. И будем долго ломать голову над тем, что же пошло не так. Не вижу в данной статье смысла глубоко лезть в загрузчик.

ЦОПП: Для чего создан центр? Какие программы уже реализуются?

Ограничимся только тем высокоуровневым кодом, который написали мы сами. Есть ли возможность написанным самим программистом кодом убить загрузчик так, чтобы он никогда не смог дойти до вызова функции main ? И на этот вопрос существует только один ответ — «Запросто!». Неучет этой возможности и приводит к очень интересным эффектам.

В данной статье мы рассмотрим самый распространенный случай — инициализацию глобальных переменных. Занимается этой операцией загрузчик, и естественно, она должна быть выполнена ДО вызова функции main . Если мы заносим в переменные какие-либо константные значения. особых проблем не возникает. Но, при инициализации переменных вполне допустимо и выполнение кода. Естественно, в таком случае написанный нами код будет выполнен ДО вызова main ! А любом коде могут быть ошибки. Вот так мы и можем убить программу до ее официального первого вздоха.

Первый, предельно грубый пример:

int g_dVar = 0;

int g_Test = 10 / g_dVar;

Как видно, инициализация глабальной переменной g_Test требует выполнения определенного кода. Как видно, в данном случае попытка ее инициализации приведет к делению на 0. И программа благополучно скончается, не дожив до функции main . Данный пример написан на С++, но и для чистого C картина будет аналогичной. В реальной жизни цепочка инициализации бывает значительно сложнее. Соответственно, намного сложнее поймать ошибки такого типа. Чаще всего это имеет место быть не с математическими операциями, как в примере, а в случае некорректной работы с указателями.

Посмотрим на пример номер 2:

int foo(void);

int g_dVar = foo();

int g_Test = 10 / g_dVar;

int foo(void)

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

Читайте также:
Qt программа что это

Зачем это все? Для чего я веду свои программы?

  1. Функция foo естественно будет заметно сложнее, чем в приведенном примере.
  2. Такая функция может возвращать результат, проверяя значительное количество условий, в том числе — определяемых динамически И вот тут и срабатывает один из стереотипов. Если эта функция реально может быть вызвана из разных мест программы, ее автор может на автомате предполагать, что все условия уже определены. так как функция main уже стартовала. А при инициализации глобальных переменных это условие не выполнено. Отсюда — высокая вероятность некорректной работы такой функции.

Конечно, глобальные переменные есть зло. И в программе на C++ обычно есть возможность полностью избежать их использования. А вот в программе на чистом C обычно такой возможности нет.

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

А теперь давайте попробуем на секунду представить, что вызываемая функция может угодить в бесконечный цикл. Или зависнет на ожидании какого-либо события. Вот тогда-то у нас и станет все совсем интересно. Никаких исключений не возникает, все с виду чинно и благородно. Только вот до функции main мы так никогда и не дойдем.

Для многих не слишком опытных программистов это ситуация шоковая, так как ошибка потенциально могла возникнуть и непосредственно в коде загрузчика. Это часто бывает, когда пишется программа для микроконтроллера. Малейшая ошибка в выборе загрузчика для конкретной версии МК может привести к такому же результату.

Ну и в качестве вишенки на торте — никто не требует, чтобы функции foo не создавала дополнительных потоков. А каждый поток, как известно имеет свою функцию, в которой тоже что-то может пойти не так.

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

Данные примеры показывают, что есть огромное различие между понятиями «точка входа» и «начало выполнения» программы. Точка входа означает всего-навсего адрес функции, которую вызовет загрузчик после завершения всех подготовительных операций. А вот написанный нами код может начать выполняться на значительно более ранних этапах работы загрузчика. В приведенных примерах это этап инициализации глобальных переменных.

В данной статье мы кратко рассмотрели проблемы, возникающие при процедурном подходе. Однако, не стоит думать, что оъектно-ориентированный подход не имеет своих собственных ловушек. В следующей статье мы рассмотрим как умереть молодым не дожив до вызова main в C++.

Источник: dzen.ru

Основы языка Си

Программа на языке Си состоит из набора директив препроцессора, определений функций и глобальных объектов. Директивы препроцессора управляют преобразованием текста до его компиляции. Глобальные объекты определяют используемые данные или состояние программы. А функции определяют поведение или действия программы. Простейшая программа на Си, которая была определена в прошлых темах:

#include int main(void)

Инструкции

Простейшим строительным элементом программы на Си являются инструкции (statements). Каждая инструкция выполняет определенное действие. В конце инструкций в языке Си ставится точка с запятой (;). Данный знак указывает компилятору на завершение инструкции. Например:

printf(«Hello METANIT.COM!»);

Вызов функции printf, которая выводит на консоль строку «Hello METANIT.COM!» является инструкцией и завершается точкой с запятой.

Читайте также:
Tile fun что это за программа и нужна ли она на Андроид

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

В этом блоке кода две инструкции. Обе инструкции представляют вызов функции printf() и выводят определенную строку на консоль.

Директивы препроцессора

Для вывода данных на консоль в примере выше используется функция printf() , но чтобы использовать эту функцию, чтобы она вообще стала нам доступна в программе на Си, необходимо в начале файла с исходным кодом подключать заголовочный файл stdio.h с помощью директивы include .

Директива include является директивой препроцессора. Кроме данной include есть еще ряд директив препроцессора, например, define.

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

Непосредственно директива «include» определяет, какие файлы надо включить в данном месте в текст программы. По умолчанию мы можем подключать стандартные файлы из каталога так называемых «заголовочных файлов», которые обычно поставляются вместе со стандартными библиотеками компилятора. И файл «stdio.h» как раз является одним из таких заголовочных файлов.

Вообще сам термин «заголовочный файл» (header file) предполагает включение текста файла именно в начало или заголовок программы. Поэтому заголовочные файлы подключаются, как правило, в начале исходного кода. Кроме того, заголовочный файл должен быть подключен до вызова тех функций, которые он определяет. То есть, к примеру, файл stdio.h хранит определение функции printf, поэтому этот файл необходимо подключить до вызова функции printf.

Но в целом директивы препроцессора необязательно должны быть размещены в начале файла.

При компиляции исходного кода вначале срабатывает препроцессор, который сканирует исходный код на наличие строк, которые начинаются с символа #. Эти строки расцениваются препроцессором как директивы. И на месте этих директив происходит преобразование текста. Например, на месте директивы #include вставляется код из файла stdio.h.

Функция main

Стартовой точкой в любую программу на языке Си является функция main() . Именно с этой функции начинается выполнение приложения. Ее имя main фиксировано и для всех программ на Си всегда одинаково.

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

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

#include void main()
#include int main()

Использование этих определений не было бы ошибкой, и программа также вывела бы строку «Hello METANIT.COM» на консоль. И для большинства компиляторов это было бы нормально.

Комментарии

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

В Си можно использовать два типа комментариев: блочный и строчный. Блочный заключается между символами /* текст комментария */ . Он может размещаться на нескольких строках. Например:

#include /* Функция main выводит на консоль строку Hello World */ int main(void)

Строчный комментарий помещается на одной строке после двойного слеша:

Читайте также:
Hashtab shell extension что это за программа

#include // подключаем заголовочный файл stdio.h int main(void) // определяем функцию main < // начало функции printf(«Hello METANIT.COM!»); // выводим строку на консоль return 0; // выходим из функции >// конец функции

Источник: metanit.com

Функция main и выполнение программ

Каждая программа C имеет основную функцию, которая должна быть названа main . Функция main служит отправной точкой для выполнения программы. Она обычно управляет выполнением программы, вызывая другие ее функции.

К функции, которая не применяется к другим функциям C, применяются main несколько ограничений. Функция main :

  • Не удается объявить как inline .
  • Не удается объявить как static .
  • Не удается принять его адрес.
  • Не удается вызвать из программы.

Сигнатура main функции

Функция main не имеет объявления, так как она встроена в язык. Если это так, синтаксис main объявления будет выглядеть следующим образом:

int main( void ); int main( int argc, char *argv[ ] ); int main( int argc, char *argv[ ], char *envp[ ] );

Функция main объявляется неявно с помощью одной из этих сигнатур. При определении main функции можно использовать любую из этих сигнатур. Компилятор Майкрософт также позволяет main иметь тип возвращаемого void значения, если значение не возвращается. Параметры argv и envp параметры, которые wmain также можно определить как тип char** . Дополнительные сведения о аргументах см. в описании аргумента.

Примечания

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

Можно объявить любую функцию, включая main параметры. Термин «параметр» или «формальный параметр» относится к идентификатору, получающему значение, передаваемое функции. Сведения о передаче аргументов в качестве параметров вы найдете в статье Параметры. Когда одна функция вызывает другую, вызываемая функция получает значения своих параметров от вызывающей функции.

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

Если вы хотите передать сведения в функцию main , параметры обычно именуются argc и argv , хотя компилятор C не требует этих имен. Традиционно, если третий параметр передается main в , этот параметр называется envp . Типы для argc , argv и envp определяются языком C. Вы также можете объявить argv как char** argv и envp как char** envp . В приведенных ниже в данном разделе примерах описывается использование этих трех параметров для доступа к аргументам командной строки. Эти параметры объясняются в следующих разделах.

Если код соответствует модели программирования Юникода, вы можете использовать версию расширенных символов main wmain Корпорации Майкрософт в качестве точки входа в вашей программе. Дополнительные сведения об этой версии расширенных символов main см. в разделе «Использование wmain «.

main Прекращения

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

Источник: learn.microsoft.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru