DNK_C_C++_Go_Rust
45 subscribers
14 photos
45 links
DNK - дневник кодера С и С++
Download Telegram
#276_PkS_TOS

Что такое операционная система?
Какие существуют типы ОС по назначению?


Операционная система (ОС) — комплекс программ, обеспечивающий управление аппаратными ресурсами компьютера и предоставляющий пользователям и прикладным программам интерфейс взаимодействия с этими ресурсами.
ОС выполняет функции посредника между пользователем и оборудованием, обеспечивая удобство работы и эффективное использование ресурсов.

Основные задачи операционной системы:
— управление процессами (планирование задач);
— управление памятью
(распределение оперативной и виртуальной памяти);
— управление устройствами ввода-вывода
(драйверы устройств)
;
— управление файловой системой
(организация хранения данных)
;
— обеспечение безопасности и защиты данных;
— предоставление
API для разработки приложений.

Типы ОС по назначению:
Универсальные (общего назначения) — предназначены для широкого круга пользователей и разнообразных задач.
Они поддерживают выполнение множества приложений и могут работать на различных устройствах, начиная от персональных компьютеров и заканчивая серверами.

Примеры:
Windows (Microsoft)
macOS (Apple)
Linux (различные дистрибутивы)


Серверные — разработаны специально для серверов и ориентированы на обеспечение высокой надежности, безопасности и производительности при работе с большими объемами данных и запросами от множества пользователей.

Примеры:
Windows Server (Microsoft)
Red Hat Enterprise Linux (RHEL)
Ubuntu Server
FreeBSD


Мобильные — предназначены для мобильных устройств, таких как смартфоны и планшеты. Они адаптированы под специфические требования этих устройств, например, ограниченные ресурсы, сенсорные экраны и длительное время автономной работы.

Примеры:
Android (Google)
iOS (Apple)
HarmonyOS (Huawei)


Встраиваемые — для встроенных систем, таких как микроконтроллеры, промышленные контроллеры, бытовая техника и автомобили.
Отличаются минимальными требованиями к ресурсам и часто работают в реальном времени.

Примеры:
RTOS (Real-time Operating System)
VxWorks
QNX
Embedded Linux


Реального времени (RTOS) — предназначены для приложений, где критически важно соблюдение временных ограничений.
Такие системы гарантируют, что задачи будут выполнены в пределах заданного временного интервала.

Примеры:
LynxOS
Integrity
RTEMS


Сетевые — используются для управления сетевыми устройствами, такими как маршрутизаторы, коммутаторы и межсетевые экраны.
Они обеспечивают безопасность и надежность передачи данных в сетях.

Примеры:
Cisco IOS
Junos OS (Juniper Networks)
VyOS

Научные и исследовательские — специальные ОС, созданные для научных исследований и вычислительной математики.
Они могут включать специализированные математические библиотеки и инструменты для обработки больших объемов данных.

Примеры:
Scientific Linux
Fedora Scientific

Каждая из этих категорий имеет свою область применения и особенности, соответствующие требованиям конкретной среды эксплуатации.
Выбор ОС зависит от задач, которые необходимо решать, и характеристик оборудования, на котором она будет использоваться.
#277_PkS_TOS

Основные составляющие и принципы работы ОС Linux как системы общего назначения.

Linux — универсальная ОС общего назначения, широко используемая на персональных компьютерах и на серверах.
П
опулярность обусловлена открытостью исходного кода, гибкостью настройки и высоким уровнем безопасности.

Основные компоненты Linux:

Ядро (Kernel) — сердце ОС, отвечающее за взаимодействие с аппаратурой и управление основными ресурсами системы.
Ядро управляет процессорами, памятью, устройствами ввода-вывода и обеспечивает базовую функциональность ОС.
В случае Linux ядро реализует следующие важные функции:
— планирование процессов;
— управление памятью;
— драйверы устройств;
— файловая система;
— сеть.


Система инициализации (Init system)отвечает за запуск необходимых служб и демонов при загрузке системы.
В современных версиях Linux наиболее популярны две системы инициализации:
Systemd;
SysVinit.


Systemd
более современная и многофункциональная система, которая заменила SysVinit во многих дистрибутивах.

Файловые системыLinux поддерживает множество файловых систем: ext4, XFS, btrfs и другие.
Файловая система организует хранение данных на дисках и обеспечивает доступ к данным.
Важнейшей особенностью файловой системы Linux является иерархическая структура каталогов, начинающаяся с корневого каталога /.

Графический интерфейс пользователя (GUI) Linux изначально был консольной ОС, но современные версии предлагают разнообразные графические оболочки: GNOME, KDE Plasma, Xfce и другие.
Графический интерфейс облегчает взаимодействие пользователя с ОС и делает ее удобной для повседневного использования.

Командная оболочка (Shell) — интерфейс для взаимодействия пользователя с ядром и утилитами системы.
Наиболее популярная оболочкаBash (Bourne Again Shell), но существуют и другие варианты: Zsh, Fish и tcsh.
Оболочка интерпретирует команды, введённые пользователем, и передает ядру для исполнения.

Утилиты и сервисыLinux поставляется со множеством утилит и сервисов, выполняющих различные задачи: управление пользователями, настройка сети, работа с файлами и многое другое.
Некоторые из них являются частью ядра, а некоторые устанавливаются отдельно.

Дистрибутивы — существует множество дистрибутивов Linux, каждый предлагает свой набор предустановленных программ, настроек и инструментов.
Популярные дистрибутивы: Ubuntu, Debian, Fedora, Arch Linux и CentOS.
Каждый дистрибутив имеет особенности и предназначен для различных целей.

Принципы работы Linux:
Многоуровневая архитектураLinux использует многоуровневую архитектуру, разделяя функции между различными уровнями.
На нижнем уровне находится ядро, которое взаимодействует непосредственно с аппаратурой.
Выше находятся уровни, ответственные за управление процессами, памятью, файловыми системами и т.д.
Верхний уровень представлен пользовательским окружением, включающим графическую оболочку и утилиты.


Многозадачность — означает возможность одновременного выполнения нескольких процессов.
Ядро планирует выполнение процессов таким образом, чтобы максимально эффективно использовать ресурсы системы.

Управление памятью — Linux использует виртуальную память, позволяющую ОС работать с большим объемом данных, чем физически доступно в оперативной памяти.
При нехватке оперативной памяти часть данных переносится на жесткий диск (свопинг).
👍1
Безопасность и права доступа Linux предоставляет развитую систему прав доступа, основанную на пользователях и группах.
Каждый файл и каталог имеют владельца, группу и набор разрешений, определяющих, кто может читать, записывать или исполнять данный файл.
Это обеспечивает высокий уровень безопасности системы.


Модульность
— многие компоненты Linux, такие как драйверы устройств, могут загружаться и выгружаться динамически, что позволяет легко добавлять новые устройства и функции без перезагрузки системы.

Открытый исходный код — одним из ключевых преимуществ Linux является открытый исходный код.
Это значит, что любой желающий может просматривать, модифицировать и распространять код системы, что способствует быстрому развитию и улучшению системы, а также привлечению большого сообщества разработчиков.

Пример работы Linux.
Рассмотрим простой сценарий загрузки и запуска системы:
Загрузка — после включения компьютера BIOS или UEFI загружают начальный загрузчик (например, GRUB).
Загрузчик находит и загружает ядро Linux в оперативную память.

Инициализация — ядро начинает выполнение и инициализирует основные подсистемы, такие как планировщик задач, менеджер памяти и драйверы устройств.
Затем запускается система инициализации (например, Systemd), которая загружает необходимые службы и демоны.

Запуск графического окружения — если настроен графический режим, то система инициализации запускает дисплейный менеджер (например, GDM для GNOME), который отображает экран входа в систему.

Вход пользователя — пользователь вводит имя и пароль, после чего система аутентифицирует его и загружает рабочее окружение (графическое или консольное).

Работа пользователя — пользователь может запускать приложения, управлять файлами, настраивать систему и выполнять другие задачи.
Все эти действия обрабатываются ядром и соответствующими сервисами.

Завершение работы — когда пользователь решает завершить работу, он может выключить компьютер или перезагрузить его. Система корректно завершит все процессы и сохранит данные перед отключением питания.

ОС Linux представляет собой мощную и гибкую операционную систему, подходящую для самых разных задач благодаря своей модульности, открытости и широкому сообществу разработчиков.
👍1
#278_C_Cpp_CMPL_GCC_PkS

Для чего нужен extern "C"?

extern "C" — в С++ директива используемая для указания компилятору, что следующая за ней функция или переменная должна быть скомпилирована с использованием соглашения о вызове функций языка C, а не C++.
Это особенно полезно при взаимодействии C++ кода с библиотеками, написанными на C, поскольку языки используют разные соглашения о вызовах функций.

Соглашения о вызове функций:
Соглашение о вызове функций (calling convention) — определяет, как параметры передаются в функцию, как возвращаются значения, и как очищается стек после завершения функции.
В C++ существует несколько соглашений о вызове функций, таких как:

cdecl (по умолчанию в C) — параметры передаются справа налево, очистка стека производится вызывающим кодом;

stdcall (используется в WinAPI) — параметры передаются справа налево, очистка стека производится функцией.

fastcall (некоторые компиляторы) — первые несколько параметров передаются через регистры, остальные — через стек.

Когда вы пишете код на C++, компилятор применяет соглашение о вызове функций, соответствующее языку C++. Однако, если вам нужно вызвать функцию из библиотеки, написанной на C, или наоборот, предоставить функцию на C++ для вызова из C-кода, необходимо использовать

extern "C",

чтобы гарантировать совместимость.

Пример использования extern "C":
Предположим, есть C-библиотека с функцией add, которую нужно использовать в вашем C++ проекте:

// C header file: mylib.h
#ifndef MYLIB_H
#define MYLIB_H

#ifdef __cplusplus
extern "C" {
#endif

int add(int a, int b);

#ifdef __cplusplus
}
#endif

#endif // MYLIB_H

Здесь мы оборачиваем объявление функции add в блок extern "C", чтобы компилятор знал, что эта функция следует соглашению о вызове функций языка C.
Таким образом, вы можете безопасно вызывать эту функцию из вашего C++ кода:

// C++ source file: main.cpp
#include "mylib.h"

int main() {
int result = add(10, 15);
return 0;
}

Если бы вы не использовали extern "C", компилятор мог бы применить C++ соглашение о вызове функций, что привело бы к ошибкам при попытке вызвать функцию из C-библиотеки.

Применение extern "C" для экспорта функций:
Также extern "C" может использоваться для экспорта функций из C++ кода, чтобы их могли вызывать из C-кода:

// C++ source file: mylib.cpp
#include "mylib.h"

extern "C" {
int add(int a, int b) {
return a + b;
}
}

Теперь функция add доступна для вызова из C-кода, так как она скомпилирована с использованием соглашения о вызове функций языка C.

Директива extern "C" — важный инструмент для обеспечения совместимости между кодом на C++ и C.
Она позволяет правильно скомпилировать и связать функции, используя нужное соглашение о вызове функций, что особенно важно при использовании внешних библиотек или создании библиотек, которые могут быть использованы в проектах на разных языках программирования.
#279_Cpp_PkS

goodbit, badbit, failbit в С++

В C++ потоки ввода-вывода (iostream) используют три флага состояния для отслеживания ошибок и других ситуаций:

goodbit — флаг указывает, что поток находится в хорошем состоянии, то есть никаких ошибок не произошло;
badbit — флаг устанавливается, когда происходит серьёзная ошибка.
Например, аппаратный сбой или потеря данных при чтении/записи;

failbit — устанавливается, если операция ввода-вывода завершилась неудачно, но без фатальных последствий.
Например, попытка чтения за пределами файла может установить
failbit.

Эти флаги можно проверить с помощью методов класса ios_base, таких как good(), bad() и fail(). Эти методы возвращают логическое значение (true или false), указывая состояние потока.

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

#include <iostream>
#include <fstream>
using namespace std;

int main() {
ifstream file("example.txt");

/* Проверка состояния потока после открытия файла */
if (!file.good()) {
cout << "Ошибка при открытии файла" << endl;
return 1;
}

string line;
while (getline(file, line)) {
cout << line << endl;

/* Проверяем состояние потока после каждой операции чтения */
if (file.bad()) {
cout << "Серьезная ошибка ввода-вывода!" << endl;
break;
} else if (
file.fail()) {
cout << "Произошла ошибка ввода-вывода." << endl;
break;
}
}

file.close();
return 0;
}


В этом примере проверятся состояние потока после открытия файла и после каждого вызова функции getline(), чтобы убедиться, что всё прошло успешно.
#280_ADM_Cpp_CRYP_DvOp_LIB

OpenSSL — библиотека криптографических функций и утилиты командной строки, широко используемые для обеспечения безопасности в интернете.
Она предоставляет инструменты для шифрования данных, аутентификации, цифровой подписи и управления сертификатами.
OpenSSL особенно популярен благодаря своей поддержке протоколов SSL/TLS, которые используются для защиты передачи данных между веб-браузерами и серверами.

Возможности OpenSSL:

Шифрование и дешифровка данныхOpenSSL поддерживает различные алгоритмы симметричного и асимметричного шифрования, такие как AES, RSA, DSA и другие.

Генерация ключей — позволяет создавать ключи для шифрования и цифровых подписей.

Цифровые сертификаты — управление цифровыми сертификатами, создание запросов на подпись сертификатов (CSR), проверка подлинности сертификатов.

Поддержка SSL/TLS — обеспечение безопасного соединения между клиентом и сервером с использованием протокола SSL/TLS.

Хэширование — поддержка хэш-функций, таких как SHA-256, MD5 и др.

Утилиты командной строки — включает набор инструментов для выполнения различных криптографических задач прямо из командной строки.

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

Генерация пары ключей RSA:
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key

Создание запроса на подпись сертификата (CSR):
$ openssl req -new -key private.key -out request.csr

Шифрование файла:
$ openssl enc -aes-256-cbc -salt -in plaintext.txt -out encrypted.bin

Проверка сертификата:
$ openssl s_client -connect example.com:443

OpenSSL является важным инструментом для разработчиков и системных администраторов, работающих с безопасностью сетевых приложений и сервисов.
#281_Cpp_CRYP_LIB

Аналоги OpenSSL.

STL в C++ не включает встроенные средства для криптографии и шифрования, подобные тем, что предоставляет OpenSSL. Однако существуют сторонние библиотеки и фреймворки, которые можно использовать для аналогичных целей в C++. Вот некоторые популярные аналоги OpenSSL в контексте C++:
1. Crypto++

Crypto++ — это бесплатная библиотека с открытым исходным кодом, предоставляющая широкий спектр криптографических примитивов и схем. Она поддерживает большинство современных алгоритмов шифрования, хэширования, цифровых подписей и многое другое. Crypto++ хорошо документирована и активно поддерживается сообществом.

Пример использования Crypto++ для шифрования с использованием AES:

#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <iostream>
#include <string>

using namespace CryptoPP;

int main() {
std::string key = "0123456789abcdef";
std::string iv = "fedcba9876543210";
std::string plainText = "Hello, World!";

CBC_Mode<AES>::Encryption encryptor((byte*)key.data(), key.size(), (byte*)iv.data());
std::string cipherText;

StringSource(plainText, true,
new StreamTransformationFilter(encryptor,
new StringSink(cipherText)));

std::cout << "Cipher Text: " << HexEncoder::Encode(cipherText) << std::endl;

return 0;
}

2. Botan

Botan — ещё одна мощная библиотека криптографических функций, написанная на C++. Она предоставляет интерфейс высокого уровня для многих криптографических операций, включая шифрование, хеширование, управление ключами и цифровыми подписями. Botan также имеет поддержку TLS.

Пример использования Botan для генерации ключа RSA:

#include <botan/botan.h>
#include <iostream>
#include <string>

int main() {
try {
using namespace Botan;

AutoSeeded_RNG rng;
RSA_PrivateKey priv_key(rng, 2048);

PKCS8_PrivateKey pkcs8_priv_key(priv_key);
std::vector<uint8_t> der_encoded = pkcs8_priv_key.DER_encode();

std::cout << "Private Key:\n" << pkcs8_priv_key.PEM_encode() << std::endl;

X509_Certificate cert(rng, "CN=Example", priv_key, 30 * Days, "SHA-256");
std::cout << "Certificate:\n" << cert.PEM_encode() << std::endl;

} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}

return 0;
}

3. LibTomCrypt

LibTomCrypt — это лёгкая и быстрая библиотека криптографических функций, написанная на чистом C, но имеющая удобные обёртки для C++. Она поддерживает множество алгоритмов шифрования, хеширования и цифровых подписей.

Пример использования LibTomCrypt для шифрования с использованием AES:

#include <tomcrypt.h>
#include <iostream>
#include <string>

int main() {
const unsigned char key[] = "0123456789abcdef";
const unsigned char iv[] = "fedcba9876543210";
const char* plainText = "Hello, World!";

symmetric_CBC cbc;
int err;

if ((err = register_cipher(&aes_desc)) != CRYPT_OK) {
std::cerr << "Failed to register AES: " << err << std::endl;
return 1;
}

if ((err = cbc_start.find_cipher("aes", find_cipher)) != CRYPT_OK) {
std::cerr << "Failed to find AES: " << err << std::endl;
return 1;
}

if ((err = cbc_setup(&cbc, key, sizeof(key), iv)) != CRYPT_OK) {
std::cerr << "Failed to setup CBC: " << err << std::endl;
return 1;
}

size_t outlen;
unsigned char* cipherText = (unsigned char*)malloc(strlen(plainText) + aes_block_length);

if ((err = cbc_encrypt(&cbc, (const unsigned char*)plainText, strlen(plainText), cipherText, &outlen)) != CRYPT_OK) {
std::cerr << "Failed to encrypt: " << err << std::endl;
free(cipherText);
return 1;
}

std::cout << "Cipher Text: ";
for (size_t i = 0; i < outlen; ++i) {
printf("%02x", cipherText[i]);
}
std::cout << std::endl;

free(cipherText);
return 0;
}

4. mbedTLS
mbedTLS — это компактная и портативная библиотека криптографических функций, изначально созданная для встраиваемых систем, но также подходящая для обычных приложений. Она предоставляет API для шифрования, хеширования, цифровых подписей и поддержки TLS.

Пример использования mbedTLS для генерации пары ключей RSA:

#include <mbedtls/rsa.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <iostream>
#include <string>

int main() {
mbedtls_rsa_context rsa;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;

mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);

const char* pers = "mbedtls_rsa_genkey";
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers));
if (ret != 0) {
std::cerr << "Failed to seed random generator: " << ret << std::endl;
goto exit;
}

ret = mbedtls_rsa_gen_key(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
if (ret != 0) {
std::cerr << "Failed to generate RSA key: " << ret << std::endl;
goto exit;
}

std::cout << "RSA key generated successfully." << std::endl;

exit:
mbedtls_rsa_free(&rsa);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);

return 0;
}


Хотя STL в C++ не предоставляет встроенные криптографические функции, существует множество сторонних библиотек, которые можно использовать для решения подобных задач. Выбор конкретной библиотеки зависит от ваших потребностей и предпочтений.
#282_Cpp_CRYP_LIB

Есть ли какие средства для работы с криптографией в Boost.

В библиотеке Boost есть модуль под названием Boost.Asio, который предоставляет средства для работы с криптографическими операциями, включая поддержку SSL/TLS. Этот модуль позволяет безопасно передавать данные по сети, используя протоколы шифрования.

Однако стоит отметить, что сам по себе Boost.Asio не предоставляет низкоуровневые криптографические функции, такие как шифрование, хеширование или работу с цифровыми подписями. Вместо этого он интегрируется с OpenSSL для предоставления этих возможностей.

Ниже приведен пример использования Boost.Asio вместе с OpenSSL для создания защищённого TCP-соединения:

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <iostream>

int main() {
boost::system::error_code ec;

boost::asio::io_service io_service;
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);

ctx.set_default_verify_paths(ec);
if (ec) {
std::cerr << "Failed to set default verify paths: " << ec.message() << std::endl;
return 1;
}

boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("example.com", "https");
auto endpoints = resolver.resolve(query, ec);
if (ec) {
std::cerr << "Failed to resolve host: " << ec.message() << std::endl;
return 1;
}

boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket(io_service, ctx);
boost::asio::connect(ssl_socket.lowest_layer(), endpoints, ec);
if (ec) {
std::cerr << "Failed to connect: " << ec.message() << std::endl;
return 1;
}

ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec);
if (ec) {
std::cerr << "Failed to perform handshake: " << ec.message() << std::endl;
return 1;
}

std::string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
boost::asio::write(ssl_socket, boost::asio::buffer(request), ec);
if (ec) {
std::cerr << "Failed to send request: " << ec.message() << std::endl;
return 1;
}

boost::asio::streambuf response_buffer;
boost::asio::read_until(ssl_socket, response_buffer, "\r\n", ec);
if (ec && ec != boost::asio::error::eof) {
std::cerr << "Failed to read response: " << ec.message() << std::endl;
return 1;
}

std::istream response_stream(&response_buffer);
std::string response;
std::getline(response_stream, response, '\0');
std::cout << response << std::endl;

return 0;
}

Объяснение примера:

Инициализация контекста SSL: Создается контекст SSL с использованием протокола sslv23, который позволяет выбирать наиболее безопасный протокол во время рукопожатия.
Настройка пути проверки сертификатов: Устанавливаются стандартные пути для поиска доверительных сертификатов.
Разрешение имени хоста: Разрешается доменное имя example.com для подключения.
Создание защищённого сокета: Создается SSL-сокет, который использует контекст SSL.
Установление соединения: Выполняется подключение к удалённому хосту.
Рукопожатие SSL: Производится рукопожатие для установления зашифрованного канала связи.
Отправка запроса: Отправляется HTTP-запрос на сервер.
Получение ответа: Получается ответ от сервера и выводится на экран.

Установка и настройка

Для компиляции и запуска этого примера вам потребуется установить Boost и OpenSSL. На большинстве Unix-подобных системах это можно сделать с помощью пакетного менеджера:

sudo apt-get install libboost-all-dev libssl-dev

На macOS с использованием Homebrew:

brew install boost openssl

После установки библиотек вы сможете скомпилировать и запустить пример с помощью g++:

g++ -o secure_connection secure_connection.cpp -lboost_system -lssl -lcrypto
./secure_connection

Этот пример показывает, как можно использовать Boost.Asio совместно с OpenSSL для создания защищённых соединений.
#283_Cpp_PkS

Как определить базовый тип лежащий в основе enum?
Как явно задать базовый тип элементов в enum?


underlying_type в С++ — используется для получения базового (основного) типа перечисления (enum) в C++.
Это делается через шаблон класса std::underlying_type, который определен в заголовочном файле <type_traits>.

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

#include <iostream>
#include <type_traits>

// Определение перечисления
enum class Color { Red, Green, Blue };

int main() {
// Получение основного типа перечисления
using UnderlyingType = std::underlying_type_t<Color>;

// Выводим значение основного типа
std::cout << "Основной тип перечисления Color: "
<< typeid(UnderlyingType).name() << std::endl;

return 0;
}

Этот код выведет основной тип перечисления Color, который по умолчанию является типом int.
Однако можно явно указать тип при определении перечисления:

enum class Color : char { Red, Green, Blue };

Теперь вывод будет соответствовать типу char.

Таким образом, std::underlying_type позволяет вам получить информацию о том, какой тип лежит в основе перечисления.
#284_C_PkS_UB

Случаи неопределенного поведения в С.

Неопределенное поведение (undefined behavior, UB) — ситуация, когда стандарт языка не определяет результат выполнения программы.

При возникновении UB компилятор может генерировать любой код, включая код, который приведет к непредсказуемым результатам.
Это делает
UB одной из самых опасных ошибок в программировании на C и C++.

Cписок распространенных случаев UB в языке C:

Достижение конца файла без чтения — если программа пытается прочитать данные за пределами конца файла, то поведение становится неопределенным.

FILE *file = fopen("example.txt", "r");
int c;
while ((c = fgetc(file)) != EOF);

Использование неинициализированных переменных — приводит к неопределенному поведению.

int x;
printf("%d\n", x); // UB


Чтение вне границ массива — обращение к элементам массива за его пределами вызывает UB.

int arr[10];
int i = 11;
printf("%d\n", arr[i]); // UB


Превышение пределов целочисленных типов превышение максимального значения целочисленного типа также ведет к неопределённому поведению.

unsigned char c = 255;
c++; // UB - undefined behavior

Указатели:
— разыменование нулевого указателя;
разыменование неинициализированного указателя. Хорошей практикой является инициализация объявленного указателя нулевым указателем.
— разыменование указателя на память, динамически выделенную с нулевым размером;
— использование указателей и ссылок на объекты с истекшим сроком жизни;
— адрессная арифметика с результатом, выходящим за границы массива и доступ к такой памяти;
— преобразование указателей в несовместимые типы
;
— разыменование висячих указателей попытка использовать указатели после освобождения памяти.

Примеры:

int *ptr = NULL;
*ptr = 42; // Неопределённое поведение

int *iptr;
*iptr = 42; // undefined behavior

int *p = malloc(sizeof(int));
free(p);
*p = 123; // UB

Ошибки при работе со строками — запись за пределы строки (например, при использовании функции strcpy), а также попытка разыменования несуществующего символа приводят к UB.

char str[5];
strcpy(str, "Hello"); // undefined behavior


Неправильное использование функций стандартной библиотеки — неправильный вызов стандартных библиотечных функций может привести к неопределенному поведению.

char *str = NULL;
sprintf(str, "%s", "Hello"); // UB


Многократное изменение одного объекта между двумя последовательными точками последовательности — поведение программы становится неопределённым, если одно и то же выражение изменяется более одного раза между двумя последовательностями операций.

int x = 0;
x = ++x + x++; // undefined behavior

Ошибка приведения типов — приведение указателя к неправильному типу может привести к неопределенному поведению.

float f = 12.34f;
int *iptr = (int *)&f;
*iptr = 56; // BU

Арифметические ошибки:
— деление на ноль;
— арифметический переполнение;
— сдвиг влево на отрицательные значения;
— сдвиг на значения превышающие размер
типа;
— приведение целого числа к не вмещающему его типу;
— попытка изменения константы — изменение значения переменной, объявленной как const;
и другие математические ошибки могут вызывать неопределенное поведение.

int a = 0;
int b = 5 / a; // BU

Переход за границы стека — переполнение стека (stack overflow), например, из-за слишком глубокой рекурсии или выделения большого объема памяти на стеке, также считается неопределенным поведением.

void recursive_function() {
/* Глубокая рекурсия может привести к неопределённому поведению */
recursive_function();
}
Препроцессор:
— непустой исходный файл, не оканчивающийся на пустую строку (или оканчивающийся на обратный слеш);
— обратный слеш после которого стоит нечто отличное от перечня Escape-кодов;
— выход за реализационные пределы (например, 1024 условия в switch);
— динамически генерируемый токен под #if.

Нарушение правил строгой алии
— нарушение правила строгого алиаса (strict aliasing rule) может приводить к неопределенному поведению.
Например, чтение данных через указатель другого типа.

int x = 42;
float *fp = (float *)&x;
*fp = 3.14159f; // undefined behavior


Эти примеры показывают лишь некоторые из возможных ситуаций, которые могут привести к неопределенному поведению.
Избегание подобных ошибок требует тщательного подхода к написанию кода и понимания особенностей языка C.
#284_C_CMPL_Cpp_DBG_GCC_PkS_UB

Санитайзеры в программировании.
-fsanitaize в GCC.


В контексте программирования термин "санитайзер" может относиться к инструментам или методам, используемым для проверки и очистки данных перед их использованием в программе.
Основная цель таких инструментов заключается в предотвращении уязвимостей безопасности: SQL-инъекции, XSS-атаки (межсайтовый скриптинг), CSRF (подделка межсайтового запроса) и других видов атак, связанных с некорректной обработкой пользовательского ввода.

Примеры применения санитайзеров:

SQL-санитайзеры — инструменты проверяют и очищают данные, поступающие от пользователя, чтобы предотвратить SQL-инъекцию.
Например, можно использовать экранирование специальных символов или параметризированные запросы, чтобы избежать выполнения вредоносных команд.

HTML/XSS-санитайзеры — для предотвращения XSS-атак используются специальные библиотеки, которые удаляют потенциально опасные HTML-теги и атрибуты из входного текста.
Это помогает защитить веб-приложения от внедрения вредоносного кода через пользовательский ввод.

CSRF-санитайзеры — защищают от подделки межсайтового запроса, часто применяются токены CSRF, которые добавляются в формы и проверяются сервером перед выполнением действий.
Санитайзеры могут автоматически генерировать такие токены и проверять их корректность.

Input Validation (валидация данных)процесс проверки того, соответствуют ли введенные пользователем данные ожидаемому формату и типу.
Например, проверка электронной почты на соответствие шаблону или ограничение длины строки.

JSON/API-санитайзеры — при работе с API важно также защищать входящие JSON-данные от возможных инъекций и атак.
Специальные библиотеки помогают проверять структуру и содержание
JSON-объектов перед их дальнейшей обработкой.

Использование санитайзеров является важной частью обеспечения безопасности приложений, так как позволяет минимизировать риски, связанные с небезопасным вводом данных со стороны пользователей.

-fsanitaize в GCC — опция, предназначеная для включения различных режимов анализа и диагностики ошибок во время компиляции и выполнения программы.
Эта опция активирует так называемые
"санитайзеры", которые помогают выявлять различные типы ошибок, такие как утечки памяти, переполнение буфера, неопределенное поведение и многое другое.

Примеры использования опции -fsanitize:

AddressSanitizer (-fsanitize=address) этот режим обнаруживает ошибки работы с памятью:
— утечки памяти;
— использование освобожденной памяти (use-after-free);
— переполнения стека;
— чтение за пределами выделенной области памяти.


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

$ gcc -g -O1 -fsanitize=address my_program.c -o my_program

ThreadSanitizer (-fsanitize=thread) — этот режим предназначен для обнаружения гонок данных (data races) в многопоточных программах.
Он помогает выявить ситуации, когда два потока одновременно пытаются изменить одну и ту же переменную без синхронизации:


$ gcc -g -O1 -fsanitize=thread my_multithreaded_program.c -pthread -o my_multithreaded_program

UndefinedBehaviorSanitizer (-fsanitize=undefined) — этот режим находит случаи неопределенного поведения в коде, например:
— деление на ноль;
— выход за пределы массива;
— неинициализированные значения.

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

$ gcc -g -O1 -fsanitize=undefined my_program.c -o my_program

LeakSanitizer (-fsanitize=leak) — этот режим ищет утечки памяти. Он работает поверх AddressSanitizer и требует его активации:

$ gcc -g -O1 -fsanitize=address,leak my_program.c -o my_program

Эти режимы позволяют разработчикам находить и исправлять ошибки до того, как они приведут к серьезным проблемам в продакшене.
Важно отметитьвключение этих опций может увеличить время компиляции и выполнение программы, поэтому рекомендуется использовать их только в процессе разработки и тестирования.
#285_C_CMPL_Cpp_DBG_GCC_PkS_UB

Анализаторы кода для С и С++

Для ЯП C и C++ существует множество анализаторов кода, которые помогают разработчикам находить потенциальные ошибки, улучшать качество кода и обеспечивать безопасность приложения:

Clang Static Analyzer — инструмент статического анализа, который поставляется вместе с компилятором Clang, интегрирован в LLVM и используется для поиска различных типов ошибок, таких как утечки памяти, неопределённое поведение, проблемы с безопасностью и т.д.:

$ clang --analyze my_code.c

cppcheck — бесплатный инструмент для статического анализа кода на языках C и C++, который фокусируется на поиске потенциальных ошибок и нарушений стандартов кодирования:

$ cppcheck my_code.cpp

Coverity Scan — коммерческий продукт компании Synopsys, предназначенный для анализа кода на предмет ошибок и уязвимостей.
Coverity Scan предоставляет бесплатную версию для проектов с открытым исходным кодом, для этого необходимо зарегистрироваться на сайте Coverity Scan и загрузить свой проект для анализа.

PVS-Studio — платформа для статического анализа кода на языках C, C++ и C#.
PVS-Studio предлагает широкий спектр проверок, включая поиск проблем с производительностью, оптимизацией и безопасностью:

$ pvs-studio-analyzer analyze -p MyProject.sln

Valgrind — набор инструментов для динамического анализа кода, который включает в себя детектор утечек памяти, профилировщик производительности и другие утилиты.
Valgrind работает под Linux и поддерживает языки C и C++:

$ valgrind --tool=memcheck ./my_program

GCC Sanitizers — компилятор GCC имеет встроенные санитайзеры (-fsanitize), которые могут быть использованы для выявления различных типов ошибок:

$ gcc -g -O1 -fsanitize=address my_program.c -o my_program

SonarQube — платформа для непрерывного контроля качества кода, которая поддерживает множество ЯП, включая C и C++.
SonarQube интегрируется с системами CI/CD и предоставляет отчёты об ошибках, нарушениях стандартов кодирования и проблемах с безопасностью.
Например для настройки проекта в SonarQube и запуск сканирования через CI/CD систему.

Linters — линтеры выполняют проверку синтаксиса и стиля кода, а также находят потенциальные ошибки.

Популярные линтеры для C/C++:

cpplint (для C++)
clang-format (для форматирования кода)
cflow (для построения графов вызовов функций)

Все перечисленные инструменты имеют свои особенности и область применения.
Выбор конкретного инструмента зависит от потребностей вашего проекта: хотите ли вы найти утечки памяти, улучшить производительность, обеспечить безопасность или просто придерживаться определённых стандартов кодирования.
#286_C_CMPL_Cpp_DBG_GCC_UB

Подопции GCC -fsanitize.

GCC -fsanitize поддерживает множество режимов анализа и диагностики ошибок.
Режимы могут иметь дополнительные параметры настройки — "подопции", которые позволяют контролировать работу санитайзеров и настраивать поведение в зависимости от требований проекта.

Основные подопции:

Подопции режима AddressSanitizer (-fsanitize=address):
1. detect_leaks=0|1|2 — включает/отключает поиск утечек памяти:
0 — отключено;
1 — только быстрые утечки (по умолчанию);
2 — все утечки.

$ gcc -g -O1 -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope detect_leaks=2 my_program.c -o my_program

2. alloc_dealloc_mismatch=0|1 — включает/отключает диагностику несоответствия между операциями выделения и освобождения памяти. По умолчанию включено.
3. new_delete_type_mismatch=0|1включает/отключает диагностику несоответствий типов при использовании операторов new и delete. По умолчанию включено.
4. nullability=0|1 — включает/отключает диагностику null-значений указателей. По умолчанию включено.
5. string=0|1 — включает/отключает диагностику строковых операций. По умолчанию включено.
6. container_overlap=0|1 — включает или отключает диагностику пересечений контейнеров. По умолчанию включено.
7. kernel_address=0|1 — включает/отключает диагностику адресов ядра. По умолчанию выключено.
8. ignorelist=<путь_к_файлу> — указывает путь к файлу с игнорируемыми функциями или областями памяти.


Подопции режима ThreadSanitizer (-fsanitize=thread):
1. detect_destroy_destroy=0|1 — включает/отключает диагностику двойного вызова деструктора. По умолчанию включено.
2. detect_data_races=0|1 — включает/отключает диагностику гонок данных. По умолчанию включено.
3. report_bugs=0|1 — включает/отключает создание отчётов о найденных багах. По умолчанию включено.
4. history_size=<размер> — устанавливает размер истории для отслеживания гонки данных. Чем больше значение, тем точнее диагностика, но и выше потребление памяти.
5. second_deadlock_stack=0|1 — включает/отключает сбор второго стека при обнаружении взаимоблокировки. По умолчанию включено.
6. atfork_enable=0|1 — включает/отключает поддержку fork(). По умолчанию включено.


Подопции режима UndefinedBehaviorSanitizer (-fsanitize=undefined):
1. signed-integer-overflow=0|1 — включает/отключает диагностику переполнений знаковых целых чисел. По умолчанию включено.
2. unsigned-integer-overflow=0|1 — включает/отключает диагностику переполнений беззнаковых целых чисел. По умолчанию включено.
3. shift-base=0|1 — включает/отключает диагностику сдвигов базовых значений. По умолчанию включено.
4. shift-exponent=0|1 — включает/отключает диагностику экспонент сдвигов. По умолчанию включено.
5. division-by-zero=0|1 — включает/отключает диагностику деления на ноль. По умолчанию включено.
6. **float-cast-overflow=0|1` — включает/отключает диагностику переполнений при преобразовании чисел с плавающей точкой. По умолчанию включено.
7. vptr=0|1 — включает/отключает диагностику виртуальных таблиц указателей. По умолчанию включено.


Подопции режима MemorySanitizer (-fsanitize=memory):
1. track-origins=0|1 — включает/отключает отслеживание происхождения ошибок. По умолчанию включено.
2. **strict-init-order=0|1` — включает/отключает строгий порядок инициализации. По умолчанию включено.
3. **strict-undef=0|1` — включает/отключает строгую проверку неопределённого поведения. По умолчанию включено.
4. **allow-read-write-mismatches=0|1` — разрешает/запрещает чтение и запись с разными типами. По умолчанию запрещено.


Подопци режима LeakSanitizer (-fsanitize=leak):
1. max_leaks=<число> — ограничивает количество отображаемых утечек памяти. По умолчанию неограниченно.
2. verbose=<уровень> — устанавливает уровень детализации сообщений. Возможные уровни: 0, 1, 2.


Подопции предоставляют гибкость в настройке поведения санитайзеров и позволяют адаптировать их под требования проекта.
#287_C_Cpp

Битовые поля в структурах в С и С++

Битовые поля в структурах позволяют экономить память, храня несколько логически независимых значений в одном байте или слове.
Битовые поля представляют собой часть структуры, которая может занимать меньше одного байта.
Это полезно, когда нужно упаковать много небольших значений в ограниченном пространстве памяти.

Битовые поля в C.
В языке C битовые поля определяются внутри структур с указанием количества битов, занимаемых каждым полем:
struct Flags {
unsigned int flag1 : 1; // 1 бит
unsigned int flag2 : 2; // 2 бита
unsigned int flag3 : 3; // 3 бита
};


Структура
Flags содержит три битовых поля:
flag1 занимает 1 бит,
flag2 занимает 2 бита,
flag3 занимает 3 бита.

Поскольку каждый бит может принимать значения 0 или 1, битовые поля могут использоваться для хранения булевых значений или небольших целых чисел.

Особенности битовых полей в C:
— порядок размещения — стандарт C не определяет точный порядок размещения битовых полей в памяти.
Это означает, что разные компиляторы могут размещать их по-разному.
— размер полей — размер битового поля должен быть меньше или равен размеру базового типа данных (например, unsigned int).
— доступ к битовым полям — доступ к битовым полям осуществляется так же, как и к обычным членам структуры.

Пример использования битовых полей в C:
#include <stdio.h>

struct Flags {
unsigned int flag1 : 1;
unsigned int flag2 : 2;
unsigned int flag3 : 3;
};

int main() {
struct Flags flags;

flags.flag1 = 1;
flags.flag2 = 2;
flags.flag3 = 5;

printf("flag1: %d\n", flags.flag1);
printf("flag2: %d\n", flags.flag2);
printf("flag3: %d\n", flags.flag3);

return 0;
}


Битовые поля в C++.
В языке C++ битовые поля работают аналогичным образом, как и в C.
Основное отличие заключается в поддержке пространства имен и классов.

#include <iostream>

struct Flags {
unsigned int flag1 : 1;
unsigned int flag2 : 2;
unsigned int flag3 : 3;
};

int main() {
Flags flags;

flags.flag1 = 1;
flags.flag2 = 2;
flags.flag3 = 5;

std::cout << "flag1: " << flags.flag1 << std::endl;
std::cout << "flag2: " << flags.flag2 << std::endl;
std::cout << "flag3: " << flags.flag3 << std::endl;

return 0;
}


Особенности битовых полей в C++:
— размещение — так же, как и в C, порядок размещения битовых полей в памяти не определен стандартом.
— размер полей — размер битового поля должен быть меньше или равен размеру базового типа данных.
— доступ к битовым полям — доступ к битовым полям осуществляется так же, как и к обычным членам класса или структуры.

Битовые поля в C и C++ являются полезным средством для экономии памяти, особенно в системах с ограниченными ресурсами.
Однако стоит учитывать, что их использование может усложнить понимание и сопровождение кода, а также привести к проблемам совместимости между платформами и компиляторами.
#288_C_Cpp_PkS_TLS

CистемЫ автоматизации билд-процесса для С и С++.

Системы автоматизации билд-процесса (или системы сборки) играют важную роль при разработке программного обеспечения на языках C и C++, особенно когда речь идет о крупных проектах с множеством зависимостей, библиотек и различных платформ.
Эти инструменты позволяют автоматизировать процесс компиляции исходного кода, а также управлять сборкой проекта, тестированием и развертыванием.

Задачи систем автоматизации билда:

Сборка исходных файлов: Компиляция всех необходимых модулей программы.
Управление зависимостями: Автоматическое скачивание и установка внешних библиотек и компонентов.
Тестирование: Запуск тестов после успешной сборки.
Оптимизация процесса: Ускорение повторной сборки путем отслеживания изменений только в тех файлах, которые были модифицированы.
Кросс-компиляция: Поддержка сборки под разные платформы и архитектуры.
Документирование: Генерация документации по проекту.
Развертывание: Подготовка собранного продукта к установке или распространению.

Популярные системы автоматизации билдов для C/C++:

MAKE — одна из самых старых и широко используемых утилит для управления процессом сборки программ, была разработана еще в начале 1970-х годов, но до сих пор остается популярной благодаря своей простоте и гибкости.
В основе работы
make лежит файл Makefile, который содержит правила сборки проекта.

Пример простого Makefile:
all: main.o helper.o
gcc -o myprogram main.o helper.o

main.o: main.c
gcc -c main.c

helper.o: helper.c
gcc -c helper.c

clean:
rm *.o myprogram

Преимущества:
простота использования для небольших проектов;
— широкая поддержка и документация;
— подходит для кросс-платформенной разработки.

Недостатки:
— сложность поддержки больших проектов;
— ограниченная функциональность по сравнению с более современными инструментами.


CMake — система генерации make-файлов и других сценариев сборки для различных платформ и компиляторов.
Вместо того чтобы писать конкретные инструкции для каждой целевой платформы, вы описываете проект в специальном языке CMake, а затем генерируете файлы сборки для нужной среды.

Пример файла CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_executable(myprogram main.cpp helper.cpp)
target_link_libraries(myprogram PUBLIC ${CMAKE_THREAD_LIBS_INIT})

Преимущества:
— поддерживает множество целевых платформ и компиляторов;
— удобен для сложных проектов с большим количеством зависимостей;
— позволяет легко генерировать проекты для
IDE, таких как Visual Studio, Xcode и др.

Недостатки:
— более сложный синтаксис по сравнению с Make;
— требует времени на освоение.


NINJA — инструмент для построения проектов, разработанный Google, не является системой управления проектами сам по себе, а скорее служит "исполнителем" задач, которые ему передаются другими системами, такими как CMake.
Ninja
известен своей высокой скоростью выполнения задач.

Пример файла build.ninja:
rule cc
command = gcc -c $in -o $out
description = CC $out

rule link
command = gcc $in -o $out
description = LINK $out

build main.o: cc main.c
build helper.o: cc helper.c
build myprogram: link main.o helper.o

Преимущества:

— очень высокая скорость сборки;
— легкий синтаксис и минималистичный подход;
— хорошо интегрируется с
CMake.

Недостатки:
— не предназначен для самостоятельного описания проекта; требует внешнего инструмента вроде CMake.
BAZEL — система сборки от Google, которая изначально разрабатывалась для внутренних нужд компании, но позже стала доступна широкой аудитории.
Bazel ориентирован на поддержку больших проектов с множеством ЯП и зависимостей.

Пример файла BUILD:

cc_binary(
name = "myprogram",
srcs = ["
main.cc", "helper.cc"],
deps = [
"//path/to/dependency:lib",
],
)

Преимущества:

— высокая производительность и масштабируемость;
— отличная поддержка модульности и повторного использования кода;
— интеграция с
Docker и Kubernetes.

Недостатки:
— довольно сложная настройка и использование;
— зависимость от специфичного языка правил
Bazel.


MESON — относительно новый инструмент для автоматизации сборки, который стремится предложить более простой и современный подход по сравнению с традиционными решениями.
Он использует язык Python для описания проекта и поддерживает различные ЯП, включая C и C++.

Пример файла meson.build:

project('MyProject', 'cpp')
executable('myprogram', ['main.cpp', 'helper.cpp'])

Преимущества:
— простой и интуитивно понятный синтаксис;
— быстрая работа и хорошая интеграция с различными
IDE.
— поддержка кросс-компиляции.

Недостатки:
— меньшая популярность по сравнению с другими инструментами;
— возможные проблемы совместимости с некоторыми старыми проектами.

Выбор системы автоматизации билд-процесса зависит от конкретных требований вашего проекта.
Для простых проектов может быть достаточно
Make, для более сложных и распределенных решений лучше подойдут такие инструменты, как CMake, Bazel или Meson.

Важно учитывать особенности каждого инструмента, его возможности и ограничения, чтобы выбрать наиболее подходящий вариант для вашей команды и проекта.
#289_Cpp

Генерация случайных чисел в С++.

Генерация случайных чисел в языке программирования C++ осуществляется с использованием стандартной библиотеки <random>.
Эта библиотека предоставляет инструменты для генерации псевдослучайных чисел с различными распределениями.

Сгенерируем случайные числа в диапазоне от 1 до 100 включительно:
— подключим заголовочный файл для работы с генератором случайных чисел и стандартными функциями ввода-вывода;
— инициализируем генератор случайных чисел — используем класс std::mt19937 (Mersenne Twister), который является одним из самых популярных генераторов случайных чисел;
— создадим распределения — определим распределение случайных чисел. В данном случае будем использовать равномерное распределение std::uniform_int_distribution;
— сгенерируем случайное число в заданном диапазоне.

Пример кода:
#include <iostream>
#include <random>

int main() {
/* Инициализируем генератор случайных чисел */
std::random_device rd;
std::mt19937 gen(rd());

/* Задаём диапазон для генерации случайных чисел */
int min = 1;
int max = 100;

/* Создаём распределение случайных чисел */
std::uniform_int_distribution<> dist(min, max);

// Генерация случайного числа
int randomNumber = dist(gen);

// Вывод результата
std::cout << "Случайное число: " << randomNumber << std::endl;

return 0;
}


Объяснение:
Заголовок <random> — содержит классы и функции для генерации случайных чисел.
Класс std::random_device — используется для создания начального числа (seed) для генератора случайных чисел. Он пытается получить истинно случайное число из аппаратных источников, если они доступны.
Класс std::mt19937 — является генератором псевдослучайных чисел, основанным на алгоритме Mersenne Twister. Мы инициализируем его с помощью rd() для обеспечения случайности.
Класс std::uniform_int_distribution — определяет равномерное распределение целых чисел в заданном диапазоне. Здесь мы задаём диапазон от 1 до 100.
Генерация случайного числа — метод dist(gen) генерирует случайное число согласно заданному распределению.

Результат:
При каждом запуске программы будет выдаваться новое случайное число в диапазоне от 1 до 100.

Дополнительные возможности:
Библиотека <random> поддерживает множество других типов распределений, например:
— нормальное распределение (std::normal_distribution)
— экспоненциальное распределение (std::exponential_distribution)
— биномиальное распределение (std::binomial_distribution)

Можно легко изменить код выше, чтобы использовать любое из этих распределений, просто заменив соответствующий класс распределения.
#290_C_CMPL_Cpp_PkS

Какая разница между статической и динамической библиотеками в С и С++?

В ЯП C и C++ библиотеки могут быть двух типов: статические (static) и динамические (dynamic).
Разница между ними заключается в том, как они компилируются и связываются с программой:

Статическая библиотека (Static Library) — представляет собой архивный файл, содержащий объектные файлы (.o), которые компилятор включает непосредственно в исполняемый файл программы во время компоновки (линковки).

Основные особенности:
Размер исполняемого файла — поскольку все необходимые функции включаются прямо в программу, размер исполняемого файла увеличивается.
Время загрузки — программе не нужно загружать дополнительные файлы при запуске, так что она может быстрее стартовать.
Обновление — для обновления кода в статической библиотеке, придется перекомпилировать всю программу заново, чтобы изменения вступили в силу.
Совместимость — программа будет работать даже без наличия самой библиотеки на целевой машине, потому что вся необходимая функциональность уже включена в исполняемый файл.

В Unix-подобных системах статические библиотеки обозначаются суффиком ".a" (от archive), а в Windows расширением ".lib".


Динамическая библиотека (Dynamic Library) — отдельный файл, который подключается к программе во время выполнения.
Динамическая библиотека содержит машинный код, который программа может использовать по мере необходимости.

Основные особенности:
Размер исполняемого файла — исполняемый файл меньше, поскольку он не содержит весь код библиотеки; вместо этого он ссылается на внешнюю библиотеку.
Загрузка времени выполнения — при запуске программы необходимо загрузить саму динамическую библиотеку, что может немного замедлить начальную загрузку.
Обновления — изменения в коде библиотеки можно внести, просто заменив её файл, без перекомпиляции основной программы.
Совместное использование — несколько программ могут одновременно использовать одну и ту же динамическую библиотеку, что экономит память и дисковое пространство.
Зависимости — для работы программы требуется наличие соответствующей динамической библиотеки на целевом компьютере.
В случае отсутствия библиотеки программа не запустится.

В Unix-подобных системах динамические библиотеки обозначаются суффиком ".so" (от shared object), в Windows расширением ".dll" (от dynamic-link library).
#291_C_CMPL_Cpp_PkS

Какая разница между исполнительным файлом и динамической библиотекой?

Исполнительный файл и динамическая библиотека имеют разные цели и способы использования в контексте программного обеспечения.

Назначение:

исполнительный файл (executable file) — программа, которую пользователь может запустить напрямую и содержит инструкции, которые ОС выполняет пошагово.
Исполнительный файл обычно имеет расширение ".exe" в Windows, а в Unix-подобных системах его тип определяется атрибутами файла, такими как права на выполнение.

динамическая библиотека (dynamic library) — набор функций и данных, которые могут использоваться несколькими программами. Библиотека загружается в память ОС по запросу исполняемых файлов и предоставляет им доступ к своим функциям.


Способ исполнения:

исполнительный файл — запускается пользователем или системой напрямую. ОС загружает его в память и начинает выполнять содержащиеся в нем команды.

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


Компоненты:

исполнительный файл — содержит все необходимые компоненты для самостоятельного выполнения, включая код, данные и ресурсы (например, иконки, строки и т.д.), а также может содержать ссылки на внешние динамические библиотеки, которые будут загружены при запуске.

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

Управление памятью:

исполнительный файл — управляет своей собственной областью памяти, выделенной ОС и сам отвечает за выделение и освобождение памяти под свои нужды.

динамическая библиотека — делегирует управление памятью вызывающему процессу. Когда программа вызывает функцию из библиотеки, эта функция работает в рамках адресного пространства процесса, вызвавшего её.

Совместное использование:

— исполнительный файл — предназначен для выполнения одной конкретной задачи.
Хотя возможно создание многозадачных приложений, каждый экземпляр исполняемого файла запускается независимо и управляет своими собственными ресурсами.


— динамическая библиотека — может быть использована сразу несколькими процессами одновременно.
Например, если два разных приложения используют одну и ту же библиотеку, ОС может загрузить её в память только один раз и предоставить доступ обоим приложениям.

Пример.
Представьте себе игру, которая использует графику и звуковые эффекты.
Игра сама по себе — это исполнительный файл, который пользователь запускает для начала игры.
Этот файл может ссылаться на различные динамические библиотеки, такие как библиотека для обработки графики (OpenGL.dll) и библиотека для воспроизведения звука (SDL_audio.so). Во время выполнения игра загружает эти библиотеки и использует их функции для отображения графики и воспроизведения звуков.

Таким образом, исполнительный файлконечный продукт, который пользователь запускает, тогда как динамическая библиотека — инструмент, используемый этим продуктом для выполнения определенных задач.