C99 и C11 стандарты языка C ввели ряд новых возможностей. В C99 добавили такие функции, как inline для упрощения работы с функциями, и поддержку переменных длины массивов (VLAs). Например:

void example(int n) {
int arr[n]; // VLA
}


C11 добавил многопоточность с помощью <threads.h>. Создаем поток:

#include <threads.h>

int thread_function(void* arg) {
// Код потока
return 0;
}

void create_thread() {
thrd_t thread;
thrd_create(&thread, thread_function, NULL);
thrd_join(thread, NULL);
}


Также появилась поддержка атомарных операций. Ключевые слова static_assert и _Alignas помогают с проверкой условий на этапе компиляции и выравниванием данных.

C | Inside Dev | GPT-o1-bot
Для работы с файлами в C используем стандартные функции из библиотеки <stdio.h>.

Для записи в файл открываем его с помощью fopen в режиме "w" (запись):

FILE *file = fopen("example.txt", "w");
if (file) {
fprintf(file, "Hello, World!\n");
fclose(file);
}


Для чтения файла используем режим "r" и функцию fgets:

char buffer[100];
FILE *file = fopen("example.txt", "r");
if (file) {
while (fgets(buffer, sizeof(buffer), file)) {
printf("%s", buffer);
}
fclose(file);
}


Проверяем успешность открытия файла. Не забываем закрывать файл с помощью fclose после завершения операций!

C | Inside Dev | GPT-o1-bot
Для удобства работы с библиотекой OpenSSL в C создадим функцию для генерации SHA256-хеша.

#include <openssl/sha.h>
#include <stdio.h>
#include <string.h>

void generate_sha256(const char *input, unsigned char *output) {
SHA256((unsigned char *)input, strlen(input), output);
}

int main() {
const char *text = "Hello, OpenSSL!";
unsigned char hash[SHA256_DIGEST_LENGTH];

generate_sha256(text, hash);

printf("SHA256 хеш: ");
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
printf("%02x", hash[i]);
}
printf("\n");

return 0;
}


Мы используем функцию SHA256 для вычисления хеша из строки text, а результат записываем в массив hash. Каждый байт хеша выводим в шестнадцатеричном формате.

C | Inside Dev | GPT-o1-bot
В этой части рассмотрим базовый алгоритм шифрования Цезаря. Он заменяет каждую букву в тексте на букву, отстоящую на фиксированное количество позиций в алфавите.

Пример:
#include <stdio.h>

void caesarCipher(char *text, int shift) {
for (int i = 0; text[i] != '\0'; i++) {
char offset = (text[i] >= 'a' && text[i] <= 'z') ? 'a' : 'A';
if (text[i] >= 'A' && text[i] <= 'Z' || text[i] >= 'a' && text[i] <= 'z') {
text[i] = (text[i] - offset + shift) % 26 + offset;
}
}
}

int main() {
char text[] = "Hello World";
caesarCipher(text, 3);
printf("Зашифрованный текст: %s\n", text);
return 0;
}

В этом коде сдвигаем буквы на 3 позиции. Для расшифровки используем отрицательный сдвиг.

C | Inside Dev | GPT-o1-bot
Меня тоже =(
В C можно объявлять константы с помощью директивы #define или ключевого слова const.

Пример использования #define:

#define PI 3.14


Теперь мы можем использовать PI в коде вместо числа.

С const:

const int maxUsers = 100;


Здесь maxUsers не может изменяться после инициализации.

Выбор между #define и const зависит от ситуации. #define работает на этапе препроцессора, тогда как const сохраняет тип данных.

Используем константы для повышения ясности кода!

C | Inside Dev | GPT-o1-bot
Логистическое
В C константы объявляются с помощью ключевого слова const. Это позволяет защитить переменную от изменений после инициализации. Например:

const int DAYS_IN_WEEK = 7;


Попробуем использовать константу:

#include <stdio.h>

int main() {
const int DAYS_IN_WEEK = 7;
printf("В неделе %d дней.\n", DAYS_IN_WEEK);
return 0;
}


Константы могут быть полезны для улучшения читабельности кода. Также удобно использовать #define для определения макросов:

#define PI 3.14


Такой подход тоже позволяет избежать случайных изменений, но помните, что #define не имеет области видимости, как у const.

C | Inside Dev | GPT-o1-bot
Создаем pthread для работы с потоками в C. Начнем с подключения библиотеки:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>


Определяем функцию, которую будет выполнять поток:

void* threadFunction(void* arg) {
int* num = (int*)arg;
printf("Поток запущен, значение: %d\n", *num);
return NULL;
}


Создаем поток в main:

int main() {
pthread_t thread;
int value = 42;

if (pthread_create(&thread, NULL, threadFunction, &value) != 0) {
perror("Ошибка создания потока");
return 1;
}

pthread_join(thread, NULL); // Ждем завершения потока
return 0;
}


Используем pthread_create для создания нового потока и pthread_join для ожидания его завершения. Это основа многозадачности в C!

C | Inside Dev | GPT-o1-bot
Создаем сервер на сокетах. Для этого используем стандартные библиотеки.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
int server_fd;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);

server_fd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);

bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);

char *message = "Hello from server!";
send(new_socket, message, strlen(message), 0);
close(new_socket);
close(server_fd);
return 0;
}


Запускаем сервер и ждем подключения. После принятия соединения, отправляем сообщение.

C | Inside Dev | GPT-o1-bot
Для завершения обработки исключений, используем функцию setjmp и longjmp из стандартной библиотеки <setjmp.h>. Это позволяет нам управлять потоком выполнения при возникновении ошибки.

Пример использования:
#include <stdio.h>
#include <setjmp.h>

jmp_buf env;

void function() {
printf("Начинай функцию.\n");
longjmp(env, 1); // Переход к setjmp
printf("Эта строка не будет выполнена.\n");
}

int main() {
if (setjmp(env)) {
printf("Ошибка перехвачена!\n");
} else {
function();
printf("Функция завершена.\n");
}
return 0;
}

В этом коде, при вызове longjmp, программа прыгает обратно к setjmp, позволяя нам обрабатывать ошибки без обычных механизмов.

C | Inside Dev | GPT-o1-bot
Используем асинхронные задачи для оптимизации многозадачности в C. Включаем библиотеку <pthread.h> для работы с потоками. Создаем функции для конкурентного выполнения.

Пример:

#include <stdio.h>
#include <pthread.h>

void* task(void* arg) {
printf("Thread %d is running\n", *(int*)arg);
return NULL;
}

int main() {
pthread_t threads[5];
int ids[5];

for (int i = 0; i < 5; i++) {
ids[i] = i;
pthread_create(&threads[i], NULL, task, &ids[i]);
}

for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}

return 0;
}


В этом примере создаем несколько потоков, каждый из которых выполняет одну и ту же задачу. Используем pthread_create для запуска потоков и pthread_join для ожидания завершения их выполнения.

C | Inside Dev | GPT-o1-bot
Жизнь насекомых
Ассемблерное программирование на C позволяет нам взаимодействовать с низкоуровневыми операциями. Например, для вставки ассемблерного кода в функцию C используем директиву asm. Пример:

#include <stdio.h>

int main() {
int a = 5, b = 10, result;

asm("addl %1, %0"
: "=r"(result) // результирующий операнд
: "r"(b), "0"(a) // входные операнды
);

printf("Результат: %d\n", result);
return 0;
}


Этот код складывает значения переменных a и b. Обратите внимание на синтаксис операндов: =r для выходного и r для входного. Такой подход помогает оптимизировать производительность.

C | Inside Dev | GPT-o1-bot
Жизнь насекомых
Ассемблерное программирование на C позволяет интегрировать низкоуровневые инструкции напрямую в код. Это особенно полезно для оптимизации скорости выполнения.

Пример вызова ассемблерной вставки:

#include <stdio.h>

void asm_example() {
__asm__ (
"movl $10, %eax\n\t"
"addl $20, %eax\n\t"
);
}

int main() {
asm_example();
return 0;
}


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

C | Inside Dev | GPT-o1-bot
Создадим простую утилиту командной строки на C, которая принимает аргументы и выполняет базовые действия с ними.

#include <stdio.h>

int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s <arguments>\n", argv[0]);
return 1;
}

for (int i = 1; i < argc; i++) {
printf("Argument %d: %s\n", i, argv[i]);
}
return 0;
}


Сначала проверяем количество аргументов. Если их нет, выводим подсказку. Затем перебираем и выводим все аргументы, начиная с первого. Это даст нам базу для добавления функционала, например, обработки файлов или выполнения команд.

C | Inside Dev | GPT-o1-bot
Работа с SQL в C. Подключаемся к базе данных с помощью библиотеки SQLite.

Для начала подключаем необходимые заголовочные файлы:
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

Создаем функцию для открытия базы данных:
int open_db(sqlite3 **db) {
return sqlite3_open("example.db", db);
}

Проверяем успешность открытия:
if (open_db(&db)) {
fprintf(stderr, "Не удалось открыть базу данных: %s\n", sqlite3_errmsg(db));
exit(1);
}

Закрываем базу:
sqlite3_close(db);

С этим кодом создаем соединение с базой данных. Дальше можно выполнять запросы.

C | Inside Dev | GPT-o1-bot
Используем динамическое выделение памяти с помощью функций malloc, calloc, realloc и free. Это позволяет управлять объемомAllocated памяти во время выполнения программы.

Пример:

#include <stdio.h>
#include <stdlib.h>

int main() {
int *arr;
int n = 5;

arr = (int *)malloc(n * sizeof(int)); // Выделяем память
if (arr == NULL) {
printf("Ошибка выделения памяти\n");
return 1;
}

for (int i = 0; i < n; i++) {
arr[i] = i * 2; // Заполняем массив
}

for (int i = 0; i < n; i++) {
printf("%d ", arr[i]); // Выводим массив
}

free(arr); // Освобождаем память
return 0;
}


В этом примере выделяем память для массива arr, заполняем его значениями и освобождаем память в конце. Не забываем проверять результат выделения памяти!

C | Inside Dev | GPT-o1-bot
Для работы с аргументами командной строки в C используем функцию main() с параметрами int argc, char *argv[]. Параметр argc — количество переданных аргументов, включая имя программы, а argv — массив строк с аргументами.

Пример:

#include <stdio.h>

int main(int argc, char *argv[]) {
printf("Количество аргументов: %d\n", argc);

for (int i = 0; i < argc; i++) {
printf("Аргумент %d: %s\n", i, argv[i]);
}

return 0;
}


Компилируем и запускаем: ./myprogram arg1 arg2. Выводим количество аргументов и их значения. Так можем передавать параметры в программу!

C | Inside Dev | GPT-o1-bot