Структура программы на языке Си
Основная точка входа программы
В языке Си, код начинает свое выполнение с главной функции, которая называется main.
Ее определение может выглядеть следующим образом:
1
2
int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
Дополнительно про main_function
Основной синтаксис программы
Фигурные скобки ‘{}’ обозначают начало и конец блока, где располагается какой-то код и в большинстве случаев они обязательны. Они нужны для того чтобы логически отделить принадлежность группы каких-то инстуркций от других блоков.
Вернемся к программе из вводного урока hello.c:
1
2
3
4
5
6
#include <stdio.h>
int main() {
printf("hello, world\n");
return 0;
}
При запуске, выполнение программы начнется с функции main. Все инструкции внутри фигурных скобок,
начиная с ‘{‘ и заканчивая ‘}’ - будут выполнятся последовательно друг за другом:
1) printf("hello, world\n");
2) return 0;
Каждая инструкция в языке Cи ДОЛЖНА заканчивается “;”.
Это настолько важно, что если пропустить ее, компилятор вам об этом сообщит:
1
2
3
4
5
6
7
8
root@fedora-develop:~/C# gcc semi_error.c -o semi_error
semi_error.c: In function ‘main’:
semi_error.c:4:27: error: expected ‘;’ before ‘return’
4 | printf("hello, world")
| ^
| ;
5 | return 0;
| ~~~~~~
Сообщит также и о неоткрытой в начале ‘{‘ фигурной скобке:
1
2
3
4
5
6
7
8
9
10
11
semi_error.c: In function ‘main’:
semi_error.c:4:5: error: expected declaration specifiers before ‘printf’
4 | printf("hello, world");
| ^~~~~~
semi_error.c:5:5: error: expected declaration specifiers before ‘return’
5 | return 0;
| ^~~~~~
semi_error.c:6:1: error: expected declaration specifiers before ‘}’ token
6 | }
| ^
semi_error.c:7: error: expected ‘{’ at end of input
Так и о не закрытой в конце:
1
2
3
4
5
root@fedora-develop:~/C# gcc semi_error.c -o semi_error
semi_error.c: In function ‘main’:
semi_error.c:5:5: error: expected declaration or statement at end of input
5 | return 0;
| ^~~~~~
Разница между инструкцией и ключевым словом
В языке Си есть такое понятие как минимальная единица синтаксиса программы, ту которую компилятор может распознать и называется это - лексема. Лексемы языка Си включают различные элементы, такие как ключевые слова, операторы, идентификаторы, литералы и так далее.
Ключевые слова
Ключевые слова - это слова, которые зарезервированы в языке и используются компилятором
для распознания каких-то определенных действий.
Например: int
, char
, if
, return
, for
Операторы
К операторам относятся арифметические операции, операции сравнения:
Например: +
, -
, *
, /
, ==
, >
, <
Идентификаторы
Это имена, которые мы задаем самостоятельно например для имен переменных или функций.
Имена поддаются определеным правилам и могут выглядеть следующим образом:
- myFunction
- my_var
- var1
Литералы
Литерал - это строка, число или символ, которое можно описать в программе следующим образом:
- 123
- “hello world”
- ‘fuck’
- 3.14
Разделительные символы
; () {} ,
Комментарии
Комментарии больше относятся к синтаксической конструкции и в языке Си есть два вида комментариев:
Многострочные: /* Это комментарий */
Однострочные: // Это комментарий
Однострочные комментарии появились начиная со стандарта C99. Ранее в языке были только многострочные комментарии, хотя в С++, многострочные комментарии появились в стандарте С++98. Комментарии никак не обрабатываются компилятором и предназначены для программистов
Последовательная обработка программы
1
2
3
4
5
6
#include <stdio.h>
int main() {
printf("hello, world\n");
return 0;
}
#include
- ключевое слово для препроцессора. Source file inclusion
<stdio.h>
- это просто файл с объявлениями функций. Данный файл можно легко найти в Linux:
1
2
3
4
root@fedora-develop:~/C# find / -name 'stdio.h' 2> /dev/null
/usr/include/c++/13/tr1/stdio.h
/usr/include/bits/stdio.h
/usr/include/stdio.h
Узнать где препроцессор будет искать эти заголовочные файлы можно следующим образом:
1
2
3
4
5
root@fedora-develop:~/C# gcc -E -Wp,-v -
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/13/include
/usr/local/include
/usr/include
Поведение препроцессора для ключевого слова #include
выглядит так:
1) Обработка #include
:
- Когда препроцессор встречает директиву
#include
, он ищет указанный файл заголовка.
2) Поиск заголовочных файлов:
Если указанный файл заголовка заключен в угловые скобки (
#include <file.h>
), препроцессор
обычно ищет файл в стандартных системных директориях для заголовочных файлов.Если файл заголовка указан в двойных кавычках (
#include "file.h"
), препроцессор
сначала ищет файл в текущем каталоге, а затем включает поиск в стандартных системных директориях.
3) Абсолютные и относительные пути:
- Если указан абсолютный или относительный путь к файлу, препроцессор использует этот путь для поиска.
int main() {
int
- это ключевое слово. В данном контексте (контексте функции) - оно обозначает возвращаемый тип, при том целочисленный, пока просто помним, что это одно из ключевых слов, типы данных будут разбираться, когда дойдем до переменных.
main
- это идентификатор но так как это основная точка входа программы
этот идентификатор можно назвать зарезервированным идентификатором.
’()’ и ‘{}’ - это Разделительные символы
printf("hello, world\n");
- функция, которая является частью стандартной библиотеки GNU C Library
Функция printf() - выводит информацию на стандартный поток вывода stdout.
В качестве аргументов, в данном случае, она принимает строку и специальный символ ‘\n’, называемый escape-последовательностью
Например ‘\n’ - переводит вывод данных на левый край новой строки.
return 0;
- эта инструкция возвращает значение из функции main, в данном примере она вернет свое значение в операционную систему. В этом можно легко убедиться и продемонстрировать скомпилировав и запустив тестовую программу hello.c:
1
2
3
4
root@fedora-develop:~/C# gcc main.c -o main
root@fedora-develop:~/C# ./main; echo $?
Hello world
0
‘0’ в контексте завершения работы программы означает ее успешное завершение. Мы можем также вернуть любое другое значение:
1
2
3
4
5
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello world\n");
return 100;
}
Проверяем:
1
2
3
4
root@fedora-develop:~/C# gcc main.c -o main
root@fedora-develop:~/C# ./main; echo $?
Hello world
100
Ненулевые значения могут использоваться для указания на различные виды ошибок или проблемы в программе.