В предыдущей части нашего занятия мы познакомились вкратце с языком C, а также установили набор инструментов для сборки проектов MinGW.
Теперь давайте попробуем создать какой-нибудь исходный код на C и получить из него функционирующую программу.
Для этого создадим каталог (папку, директорий) где-нибудь, например, с именем MYPROG01 и создадим в данном каталоге файл с именем, например, main.c, так как файлы с исходным кодом принято создавать с расширением .c. Файл мы создадим вот такого содержания
1 2 3 4 5 6 7 |
#include <stdio.h> int main() { printf("Hello, World!!!rn"); return 0; } |
Это и будет наша первая программа, которая выведет в консоль текст Hello, World!!!, а также возвратит каретку и переведёт строку благодаря специальным символам 'r' и 'n'.
Что же находится в нашем исходном коде.
Для начала мы подключаем файл stdio.h, в котором находятся прототипы (пока можете не вдаваться в значение этого слова, позже мы с прототипами будем работать сами постоянно) функций стандартной библиотеки C, связанной с вводом-выводом.
Далее идёт функция (в C все подпрограммы обёртываются в функции, об этом мы также поговорим позже) main(), которая является точкой входа в нашу программу и любая программа в C всегда начинает выполняться именно с этой функции. У функции есть имя main, служащее для того, чтобы функцию можно было вызвать откуда-либо, также есть параметры входящие, которые заключены в круглые скобки (в нашем случае функция никаких параметров не принимает), а также один возвращаемый параметр какого-либо типа (в нашем случае int – целочисленный знаковый тип, о типах мы тоже будем говорить позже). Также у любой функции, а наша функция тому не исключение есть тело – это часть функции, заключенная в фигурные скобки. В теле идут друг за другом команды, которые говорят "программе", что она должна делать в данный момент.
Первая команда
1 |
printf("Hello, World!!!rn"); |
вызывает функцию стандартной библиотеки ввода-вывода printf, которая отправляет в средство стандартного вывода строку. В строке также могут быть использованы символы форматирования, с которыми мы познакомимся позже. Также здесь у нас использованы специальные символы возврата каретки и перевода строки, о которых я писал выше.
Следующая команда
1 |
return 0; |
возвращает аргумент при выходе из функции. Возвращаем 0, что также является целым числом.
Задача MinGW – преобразовать файл с исходным кодом в исполняемый типа exe.
Откроем консоль (командную строку), находясь в нашем каталоге и, оказывается для нашей операции вполне достаточно одной команды gcc, в параметрах которой мы указываем файл с исходным кодом
В случае успеха у нас появится файл с именем a.exe в текущем каталоге
Проверим работу программы введя в консоли команду с именем исполняемого файла, расширение .exe можно не вводить. Мы получим следующий результат
Отлично! Наша программа работает.
Также мы можем назначить любое имя для выходного файла в параметре с помощью ключа -o (расширение можно также не вводить). Удалим a.exe и введём команду
У нас появится файл с нужным нам именем
Работоспособность его будет такая же, так как это тот же файл, только с другим именем
Как вообще происходит процесс создания исполняемого файла из файла (файлов) с исходным кодом?
Первый этап – это трансляция, которая превращает исходный код в объектный, и создаётся файл (или несколько файлов) с расширением -o.
Второй этап – это компоновка или линковка. На данном этапе объектный файл (или несколько) компонуется (компонуются) в один исполняемый файл.
Причём первый этап мы можем разбить на несколько этапов, так как трансляция тоже происходит не единовременно. Сначала происходит препроцессинг, где в одно целое собирается весь исходный код, в том числе код из подключенных файлов с помощью директивы #include. Далее идёт создание ассемблерного файла (или нескольких), а уже затем из ассемблерного файла (или нескольких) формируется объектный файл (или несколько).
Давайте попробуем теперь наш исполняемый файл создать в несколько этапов, благо нам это сделать MinGW вполне позволяет.
Удалим файл myprog.exe, чтобы у нас в директории остался лишь файл main.c.
Затем введём вот такую команду, которая нам сформирует файл main.i со всем кодом, в т.ч. подключенным, в результате препроцессинга
Судя по размеру полученного файла, мы понимаем, сколько кода нам в него добавил препроцессор
Покажу лишь часть кода в этом файле, остальной посмотрите у себя
1 2 3 4 5 6 7 8 9 10 11 12 |
# 210 "c:\mingw\include\stdio.h" 3 typedef struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; } FILE; |
Далее мы из этого файла можем получить ассемблерный (main.s) с помощью следующей команды
Откроем данный файл и посмотрим его содержимое
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
.file "main.c" .text .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "Hello, World!!!15" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: LFB11: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp call ___main movl $LC0, (%esp) call _puts movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc LFE11: .ident "GCC: (MinGW.org GCC-8.2.0-3) 8.2.0" .def _puts; .scl 2; .type 32; .endef |
Пока нам здесь мало что понятно, но до ассемблера мы когда-нибудь, надеюсь, тоже доберёмся.
Теперь непосредственно компиляция. Для создания объектного файла main.o дадим следующую команду
Имя выходного файла мы не указываем, так как по умолчанию формируется файл с тем же именем, что и исходный, если нужно какое-то другое имя на выходе, то можно использовать ключ -o.
Мы видим, что у нас появился объектный файл
Содержимое объектного файла мы смотреть не будем, так как мы там ничего не увидим, он близок по содержимому к исполняемому.
Затем мы уже производим линковку (создаём исполняемый файл из объектного (или нескольких))с помощью следующей команды
После данной команды у нас появился исполняемый файл
Это тот же файл, который мы получили в результате однопроходной сборки в самом начале. Только тут мы прошли все этапы сборки. Сейчас нам от этого мало толку, но когда у нас будет много файлов (модулей) с исходным кодом, а также будет подключение внешних статических и (или) динамических библиотек, то это будет уже очень актуально.
Также в результате поэтапной сборки мы можем применить некоторые опции, например изменить уровень оптимизации кода, используя ключи -O0, -O1, -O2, -O3 при создании объектного файла (или нескольких).
Назначение различных уровней оптимизации описано много где, например вот тут.
Я пробовал различные уровни в случае формирования исполняемого кода из исходного файла нашего занятия. Результат мало чем отличается, так как у нас и кода-то особого нет. А в случае написания программ с огромным количеством кода оптимизация сильно помогает. Хотя всю отладку программ на этапе их создания и тестирования лучше производить с отключенной оптимизацией (без использования ключа, так как по умолчанию оптимизация отключена, либо с ключом -O0).
Итак, на данном занятии мы установили набор инструментов для написания программ для Windows на языке C, а также попробовали на практике создать рабочую программу, пусть пока простую, но для кого-то простая программа, если она у него самая первая имеет гораздо больший интерес, чем сложная рабочая программа для тех, кто занимается программированием уже давно.
Всем спасибо за внимание!
Предыдущая часть Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
Здравствуете спасибо за познавательные видео уроки и статьи. Возможна ли на MinGW программировать компьютерной графикой и начать самого простого вывод на экран пикселя? А то как то скучна решат задачи без рисования графиков , фракталов и.т.д
Спасибо за интерес!
Можно конечно, практически весь функционал Windows, весь его API здесь доступен. Но к тому времени, когда мы будем писать графику, я думаю мы уже освоим сценарии и будем работать в среде.
Чем то anjuta напоминает только она в Linux.
Здравствуйте, во первых хотел сказать спасибо вам большое за познавательные уроки!
во вторых хотел спросить, почему в ходе создании ассемблерного файла main.s из main.i (команда gcc -S main.i -o main.s) у меня не создается main.s? выдается куча варнингов такого типа "main.i:901:15: warning: null character(s) ignored"
Здравствуйте!
Спасибо!
Может в качестве кавычек другой символ? Проект мой собираете или сами писали?
код я точно как у нас написал, и проект тоже сам создал. Я смотрю у вас windows 7, а у меня 10, может проблема в этом?
у вас*
Ну и объясните мне, почему спец символы не работают?
Потому что их WordPress покоцал
printf("Hello, World!!!rn");
"..Отлично! Наша программа работает…"
Программа не работает, просит ввести .\ перед именем программы.
Как-то все немного не так да?
При попытке скомпилировать программу ничего не компилируется, выводится только
d:\MYPROG01>gcc main.c
C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingw32.a(setargv.o):(.text+0x3d): undefined reference to
__chkstk_ms'
__chkstk_ms'C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingwex.a(glob.o):(.text+0x709): undefined reference to
C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingwex.a(glob.o):(.text+0x777): undefined reference to
__chkstk_ms'
__chkstk_ms'C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingwex.a(glob.o):(.text+0x90d): undefined reference to
C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingwex.a(glob.o):(.text+0x955): undefined reference to
__chkstk_ms'
__chkstk_ms' followC:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingwex.a(glob.o):(.text+0x9e7): more undefined references to
collect2: ld returned 1 exit status
d:\MYPROG01>
переменную среды C:\MinGW\bin добавил.
Что-то не то с путями, или недоустановилась сборка.
Здравствуйте вопрос такой будет ли исполняемый файл созданный в линукс работать в виндовс и наоборот и если нет то почему и как заставить его работать
Исполняемый файл не будет, а вот если наш проект пересобрать в Linux, то для Linux сформируется свой исполняемый файл, который будет так же успешно работать. Исполняемые файлы не мультиплатформенны из-за разной реализации ядер.
Автор , вот установил пакеты Mingw , хорошо , а дальше в какой программе создавать файлы ?
Атмел студио или кодвижнавр или другая программа ?
В строке команды printf есть ошибка. Hello, World!!!rn вместо Hello, World!!!\r\n
Это WordPress казючит.
Установил MinGW c оффсайта. При компиляции защитник Виндовс говорит, что в исполняемом файле троян. Проверил на сайте вирустотал исполняемый файл, 22 антивируса говорят, что заражен. Битдефендер говорит что заражен: Файл G:\a.exe заражен Gen:Variant.Ursu.8410
Добрый день!
Не могли бы вы подсказать. Ситуация такова.
Установил MinGW с оффсайта ссылки на который на этом сайте. После компиляции программы, Защитник Виндовс (Виндовс 10) в исполняемом файле обнаружил троян. Я проверил скомпилированный файл на онлайн сервисе virustotal 22 из 70 антивирусов обнаружили троян. На работе проверил платным Битдефендер, он обнаружил Файл G:\a.exe заражен Gen:Variant.Ursu.8410.
Думаю, что данный вопрос лучше решать с разработчиками пакета, а также с разработчиками антивирусов.
Спасибо.
Здравствуйте. Большое вам спасибо за вашу работу. С помощью вас начал программировать микроконтроллеры. Только вот большие пробелы в знание языка СИ. Как раз для таких как я, вы начали цикл уроков по основам языка Си. Я запнулся уже на первом уроке. Скачал и установил компилятор MinGW. Повторяя в один в один, шаг за шагом. Запустил консоль прописал путь. Тут полезли ошибки. Вот одна из них cannot find crt 2.o:find such or directory. И так далее. Помогите сдвинутся с мертвой точки.
Команда линковки и назначения нового имени одна и таже, это вызывает некоторую путаницу, а вообще материал хорошо преподносится..