generated from cotes2020/chirpy-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
236 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
--- | ||
title: Структура программы на языке Си | ||
date: 2023-12-07 00:00:00 +0300 | ||
categories: [Programming, С] | ||
tags: [c] | ||
pin: false | ||
author: spybull | ||
--- | ||
|
||
## Структура программы на языке Си | ||
|
||
|
||
### Основная точка входа программы | ||
|
||
В языке Си, код начинает свое выполнение с главной функции, которая называется **main**. | ||
Ее **определение** может выглядеть следующим образом: | ||
|
||
``` | ||
int main(void) { /* ... */ } | ||
int main(int argc, char *argv[]) { /* ... */ } | ||
``` | ||
|
||
Дополнительно про [main_function](https://en.cppreference.com/w/c/language/main_function) | ||
|
||
|
||
### Основной синтаксис программы | ||
Фигурные скобки '{}' обозначают начало и конец блока, где располагается какой-то код и в большинстве случаев они обязательны. | ||
Они нужны для того чтобы логически отделить принадлежность группы каких-то инстуркций от других блоков. | ||
|
||
Вернемся к программе из вводного урока [hello.c]({% post_url 2023-12-06-introduction to c %}#первая-программа): | ||
|
||
``` | ||
#include <stdio.h> | ||
int main() { | ||
printf("hello, world\n"); | ||
return 0; | ||
} | ||
``` | ||
|
||
При запуске, выполнение программы начнется с функции **main**. Все инструкции внутри фигурных скобок, | ||
начиная с '{' и заканчивая '}' - будут выполнятся последовательно друг за другом: | ||
|
||
1) `printf("hello, world\n");` | ||
2) `return 0;` | ||
|
||
Каждая **инструкция** в языке Cи **ДОЛЖНА** заканчивается ";". | ||
Это настолько важно, что если пропустить ее, компилятор вам об этом сообщит: | ||
``` | ||
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; | ||
| ~~~~~~ | ||
``` | ||
|
||
Сообщит также и о неоткрытой в начале '{' фигурной скобке: | ||
``` | ||
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 | ||
``` | ||
|
||
Так и о не закрытой в конце: | ||
``` | ||
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; | ||
| ^~~~~~ | ||
``` | ||
|
||
## Разница между инструкцией и ключевым словом | ||
|
||
В языке Си есть такое понятие как **минимальная единица синтаксиса программы**, ту которую компилятор может распознать и называется это - [**лексема**](https://ru.wikipedia.org/wiki/%D0%9B%D0%B5%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7). Лексемы языка Си включают различные элементы, такие как ключевые слова, операторы, идентификаторы, литералы и так далее. | ||
|
||
### Ключевые слова | ||
Ключевые слова - это слова, которые зарезервированы в языке и используются компилятором | ||
для распознания каких-то определенных действий. | ||
|
||
Например: `int`, `char`, `if`, `return`, `for` | ||
|
||
### Операторы | ||
К операторам относятся арифметические операции, операции сравнения: | ||
|
||
Например: `+`, `-`, `*`, `/`, `==`, `>`, `<` | ||
|
||
### Идентификаторы | ||
Это имена, которые мы задаем самостоятельно например для имен переменных или функций. | ||
Имена поддаются определеным правилам и могут выглядеть следующим образом: | ||
|
||
- myFunction | ||
- my_var | ||
- var1 | ||
|
||
### Литералы | ||
Литерал - это строка, число или символ, которое можно описать в программе следующим образом: | ||
|
||
- 123 | ||
- "hello world" | ||
- 'fuck' | ||
- 3.14 | ||
|
||
[WIKI](https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%82%D0%B5%D1%80%D0%B0%D0%BB_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)) | ||
|
||
### Разделительные символы | ||
```; () {} ,``` | ||
|
||
|
||
### Комментарии | ||
Комментарии больше относятся к синтаксической конструкции и в языке Си есть два вида комментариев: | ||
|
||
Многострочные: | ||
`/* Это комментарий */` | ||
Однострочные: | ||
`// Это комментарий` | ||
|
||
Однострочные комментарии появились начиная со стандарта **C99**. Ранее в языке были только многострочные комментарии, хотя в С++, многострочные комментарии появились в стандарте **С++98**. | ||
Комментарии никак не обрабатываются компилятором и предназначены для программистов | ||
|
||
|
||
## Последовательная обработка программы | ||
|
||
``` | ||
#include <stdio.h> | ||
int main() { | ||
printf("hello, world\n"); | ||
return 0; | ||
} | ||
``` | ||
|
||
`#include` - ключевое слово для [препроцессора]({% post_url 2023-12-06-introduction to c %}#препроцессинг). [Source file inclusion](https://en.cppreference.com/w/cpp/preprocessor/include) | ||
|
||
`<stdio.h>` - это просто файл с объявлениями функций. Данный файл можно легко найти в Linux: | ||
``` | ||
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 | ||
``` | ||
|
||
Узнать где препроцессор будет искать эти заголовочные файлы можно следующим образом: | ||
``` | ||
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](https://www.gnu.org/software/libc/) | ||
|
||
Функция [printf()](https://man7.org/linux/man-pages/man3/printf.3.html) - выводит информацию на стандартный поток вывода **stdout**. | ||
В качестве аргументов, в данном случае, она принимает строку и специальный символ '**\n**', называемый [escape-последовательностью](https://en.wikipedia.org/wiki/Escape_sequences_in_C) | ||
|
||
Например '**\n**' - переводит вывод данных на левый край новой строки. | ||
|
||
`return 0;` - эта инструкция возвращает значение из функции **main**, в данном примере она вернет свое значение в операционную систему. | ||
В этом можно легко убедиться и продемонстрировать скомпилировав и запустив тестовую программу [hello.c]({% post_url 2023-12-06-introduction to c %}#первая-программа): | ||
|
||
``` | ||
root@fedora-develop:~/C# gcc main.c -o main | ||
root@fedora-develop:~/C# ./main; echo $? | ||
Hello world | ||
0 | ||
``` | ||
|
||
**'0'** в контексте завершения работы программы означает ее **успешное завершение**. | ||
Мы можем также вернуть любое другое значение: | ||
|
||
``` | ||
#include <stdio.h> | ||
int main(int argc, char* argv[]) { | ||
printf("Hello world\n"); | ||
return 100; | ||
} | ||
``` | ||
|
||
Проверяем: | ||
``` | ||
root@fedora-develop:~/C# gcc main.c -o main | ||
root@fedora-develop:~/C# ./main; echo $? | ||
Hello world | ||
100 | ||
``` | ||
Ненулевые значения могут использоваться для указания на различные виды ошибок или проблемы в программе. | ||
|
||
|
||
## Литература | ||
- [K&R ANSI C](https://kremlin.cc/k&r.pdf) | ||
- [Ахо, Сети, Ульман. Компиляторы. Принципы, технологии, инструменты.2ed.2008.pdf](https://github.com/lehaSVV2009/Compiler/blob/master/books/%D0%90%D1%85%D0%BE%2C%20%D0%A1%D0%B5%D1%82%D0%B8%2C%20%D0%A3%D0%BB%D1%8C%D0%BC%D0%B0%D0%BD.%20%D0%9A%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%82%D0%BE%D1%80%D1%8B.%20%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF%D1%8B%2C%20%D1%82%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8%2C%20%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B.2ed.2008.pdf) | ||
- [Про потоки streams](https://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html) | ||
- [Lex и YACC в примерах](https://rus-linux.net/lib.php?name=/MyLDP/algol/lex-yacc-howto.html) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.