From 1640c3a6d278ce5206c184d437759e01da30f4a3 Mon Sep 17 00:00:00 2001 From: FelPrim Date: Sun, 28 Dec 2025 00:10:39 +0300 Subject: [PATCH] changes --- 1hello_world/hello.c | 16 ++++++++ 2exitcode/exitcode.c | 13 ++++++ 3variables/variables.c | 92 ++++++++++++++++++++++++++++++++++++++++++ README.md | 8 +++- hello_world/hello.c | 6 --- 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 1hello_world/hello.c create mode 100644 2exitcode/exitcode.c create mode 100644 3variables/variables.c delete mode 100644 hello_world/hello.c diff --git a/1hello_world/hello.c b/1hello_world/hello.c new file mode 100644 index 0000000..46672be --- /dev/null +++ b/1hello_world/hello.c @@ -0,0 +1,16 @@ +// объявление внешней функции puts, которая печатает строку str +int puts(char* str); + +// функция main - главная функция +int main(){ + // вызов функции puts + puts("Hello, World!"); +} + +// Для компиляции нужно в терминале написать `tcc hello.c` +// Для запуска нужно в этом же терминале написать `hello.exe` + +/* +"//" обозначают комментарии, они не влияют на то, какой будет программа +Также C поддерживает комментарии-блоки (как этот), но не поддерживает их как вложенные +*/ \ No newline at end of file diff --git a/2exitcode/exitcode.c b/2exitcode/exitcode.c new file mode 100644 index 0000000..b406812 --- /dev/null +++ b/2exitcode/exitcode.c @@ -0,0 +1,13 @@ +// Вывод в консоль, на самом деле, нетривиальная задача. Поэтому мы были вынуждены использовать внешнюю функцию puts в прошлом примере. +// Поэтому напишем программу, которая что-то делает, но без вывода в консоль + +int main(){ + return 1+2; +} + +// Для компиляции: `tcc exitcode.c` +// Для запуска: `exitcode.exe` +// Для того, чтобы увидеть результат, который вернула программа, в cmd нужно написать `echo %ERRORLEVEL%` сразу после предыдущей команды. + +// Вообще, обычно main возвращает код статуса результата выполнения программы. +// Так 0 соответствует успешному выполнению, не 0 - коду какой-то ошибки (что-то подобное происходит на сайтах при показе ошибок 404 и т.д.) diff --git a/3variables/variables.c b/3variables/variables.c new file mode 100644 index 0000000..a3dadd7 --- /dev/null +++ b/3variables/variables.c @@ -0,0 +1,92 @@ +int main(){ + // переменная типа int (integer) с именем a + int a = 1; + int b = 2; + return a+b; +} + +// напоминаю, `echo %ERRORLEVEL%` после запуска + +// Базовые "элементарные" типы: +int unused_code(){ + char symbol = 'a'; // ASCII символ. Практически, это все символы на клавиатуре кроме кириллицы + float number = 2.3; // дробное число + unsigned int notnull = 2; // целое беззнаковое число. + + // Строка в C определяется как массив ASCII символов, который заканчивается символом конца строки '\0'. + // Я не хочу сейчас говорить про массивы, т.к. они связаны с понятием указателя, поэтому отмечу только следующее: + char string1[] = {'S', 't', 'r', 'i', 'n', 'g', '\0'}; // так выглядит создание массива с заранее заданными значениями + char string2[] = "String"; // для строк есть более удобный синтаксис. строка 2 хранит то же самое, что и строка 1 + + // Что можно делать с переменными, кроме как создавать? + + int c; // их можно задавать без указания значения. Тогда их байты могут быть + // как случайными (заполнеными мусором), так и заполнеными нулями, но на это лучше не полагаться + + c = notnull; // в данном примере проблемы нет, так как у notnull значение 2, но + // если у переменных разный тип, то нет гарантии того, что присваивание значения + // одной переменной другой будет выполнять то, что вы думаете + c = number; // нам не нужно указывать, что у c тип int, т.к. это уже было сделано ранее. + // Аналогично, т.к. int может хранить значение 2, то в данном контексте операция законна, + // но не для любого float так можно делать. + + // Т.к. компьютер воспринимает все примитивные типы как числа, то: + // Можно применять побитовые логические операции (число считается за вектор битов): + int a = 5, b = 3; + // ЛОГИЧЕСКОЕ И: &, ЛОГИЧЕСКОЕ ИЛИ: |, XOR: ^, ЛОГИЧЕСКОЕ НЕ: ~ + c = a&b; // c = 0b...0101 & 0b...0011 = 0b...0001 = 1 + c = a|b; // c = 0b...0101 | 0b...0011 = 0b...0111 = 7 + c = a^b; // c = 0b...0101 ^ 0b...0011 = 0b...0110 = 6 + c = ~a; // зависит от числа байт в int. Так-то не знаем, но на x86_64 процессорах int это 4 байта. Тогда: + // c = ! 0b 00000000_00000000_00000000_00000101 = 0b 11111111_11111111_11111111_11111010 = ? + // Начиная с C23 (последнего стандартно) в языке регламентировано то, что 1 бит соответствует знаку -. + // Тогда если все биты 1 - то получится -1, если первый бит 1 а остальные 0 - получится -2^{число битов -1}. 4 байта->32 бита -> -2^31 + // 0b 11111111_11111111_11111111_11111010 = 0b 11111111_11111111_11111111_11111111 - 0b...0101 = -1 - 5 = -6 + // По сути, для целых чисел ~x === -x-1 + // float устроены внутри себя гораздо сложнее, чем целочисленные типы, лучше с ними такого не делать + + + // сдвиг влево/вправо: << и >> + c = a << 1; // c = 0b...0101 << 1 = 0b...01010 = 10 + // по сути, для целых чисел x << y = x * 2^y + c = a >> 1; // c = 0b...0101 >> 1 = 0b...010 = 2 + // по сути, для целых чисел x >> y = x / 2^y + + // просто логические операторы. Тогда, с точки зрения C, false = 0, не false (т.е. true) = не 0: + // ЛОГИЧЕСКОЕ И: &&, ЛОГИЧЕСКОЕ ИЛИ: ||, ЛОГИЧЕСКОЕ НЕТ: ! + c = a && b; // 1, т.к. оба истина + c = 0 && a; // 0, т.к. есть ложь. При этом a даже не вычисляется (всё ради оптимизаций) + c = 0 || 0; // 0, т.к. оба ложь + c = a || 0; // 1, т.к. есть истина. Правое значение тоже не вычисляется + c = !a; // 0, т.к. a - истина + + // операторы сравнения + c = a==b; // 0, т.к. a > b + c = a!=b; // 1, т.к. a > b + c = a>b; // 1, т.к. a > b + c = a>=b; // 1, т.к. a > b + c = a b + c = a<=b; // 0, т.к. a > b + + float nan = 0.0/0.0; // за счёт '.' компилятор понимает, что 0.0 - это float, а не int + float inf = 1.0/0.0; + float negative_inf = -inf; + float negative_zero = -1/0/inf; + + c = nan==nan; // ложь. Аналогично с >= и <= + c = nan!=nan; // истина + c = negative_inf==inf; // ложь + c = negative_zero==0.0; // истина + c = 1.0/0.0 == 1.0/negative_zero; // ложь (т.к. negative_inf != inf) + + // арифметические действия + c = a+b; + c = a-b; + c = a%b; // остаток от деления. 5 % 3 = 2. При этом, почему-то, -5%3 = -2, а не 1 + с = a/b; // целочисленное деление. 5/3 = 1. При этом -5/3 = -1. + // a == b*(a/b)+a%b (если b != 0) + // для дробных чисел, конечно же, не выполняется, т.к. они связаны с неточными вычислениями. + // возведения в степень нет + + return 0; +} diff --git a/README.md b/README.md index c9ade05..8154efa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ Ориентировочная ОС: Windows Ориентировочный текстовый редактор: Notepad++$^1$ -Ориентировочный компилятор: tcc$^2$ +Ориентировочный компилятор: tcc$^2$ 1: Спрашивайте лично/используйте интернет/другой редактор -2: https://github.com/phoenixthrush/Tiny-C-Compiler/releases/tag/0.9.27-win64 \ No newline at end of file +2: https://github.com/phoenixthrush/Tiny-C-Compiler/releases/tag/0.9.27-win64 Советую добавить его в PATH$3$: +Изменение переменных среды текущего пользователя +PATH: добавить путь к папке, в которой лежит tcc.exe +После этого в консоли можно проверить, находится ли он в PATH, через команду +tcc -v \ No newline at end of file diff --git a/hello_world/hello.c b/hello_world/hello.c deleted file mode 100644 index a1cd8b3..0000000 --- a/hello_world/hello.c +++ /dev/null @@ -1,6 +0,0 @@ -int puts(char *str); - -int main(){ - puts("Hello, World!"); - return 0; -}