#275_Cpp_PkS
Что такое сериализация?
Какие библиотеки знаете C++?
СЕРИАЛИЗАЦИЯ — процесс преобразования структуры данных или объекта в формат, пригодный для хранения или передачи (например, в файл или по сети).
Этот формат обычно представляет собой последовательность байтов, которую можно восстановить обратно в исходную структуру данных или объект позже.
ДЕСЕРЕАЛИЗАЦИЯ — процесс обратного восстановления данных из сериализованного формата.
Зачем нужна сериализация:
Хранение данных — позволяет сохранять объекты в файлах для последующего использования.
Передача данных — обмен данными между различными системами или приложениями, работающими на разных платформах.
Кэширование — сохранение промежуточных результатов вычислений для ускорения последующих запросов.
Отладка и мониторинг — запись состояний системы для анализа и диагностики.
Примеры библиотек для сериализации в C++:
Boost.Serialization — библиотека, входящая в состав Boost, которая предоставляет мощные средства для сериализации и десериализации объектов C++.
Поддерживает различные форматы, включая текстовые файлы, бинарные данные и архивы.
Пример использования:
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
class Person {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & name;
ar & age;
}
public:
std::string name;
int age;
};
int main() {
Person person{"John", 30};
std::ofstream ofs("person.txt");
boost::archive::text_oarchive oa(ofs);
oa << person;
return 0;
}
Сereal — современная библиотека для сериализации в C++, которая поддерживает множество различных форматов, таких как JSON, XML, binary и другие.
Легко интегрируется с популярными контейнерами STL и пользовательскими типами.
Пример использования:
#include <cereal/archives/json.hpp>
#include <fstream>
struct Person {
std::string name;
int age;
template<class Archive>
void serialize(Archive & archive) {
archive(CEREAL_NVP(name), CEREAL_NVP(age));
}
};
int main() {
Person person{"Jane", 25};
std::ofstream os("person.json");
cereal::JSONOutputArchive oarchive(os);
oarchive(person);
return 0;
}
Google Protocol Buffers (Protobuf) — кросс-платформенная система сериализации структурированных данных, разработанная компанией Google.
Протобуферы обеспечивают компактное представление данных и высокую производительность.
Пример использования:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}
Затем этот .proto файл нужно скомпилировать в C++ код с помощью protoc компилятора.
Thrift (Apache Thrift) — фреймворк для создания высокопроизводительных сервисов и систем обмена сообщениями, который также включает поддержку сериализации.
Thrift генерирует код на основе определения интерфейса, написанного на специальном языке.
Пример использования:
namespace cpp example
struct Person {
1: required string name,
2: optional i32 age,
}
Затем этот .thrift файл нужно скомпилировать в C++ код с помощью thrift компилятора.
FlatBuffers — библиотека от Google, предназначенная для эффективной сериализации и десериализации структурированных данных.
Отличается тем, что данные хранятся в одном буфере, что позволяет быстро обращаться к ним без необходимости полной десериализации.
Пример использования:
#include "flatbuffers/flatbuffers.h"
#include "Person_generated.h"
int main() {
flatbuffers::FlatBufferBuilder builder;
auto name = builder.CreateString("Alice");
auto age = 20;
auto person = CreatePerson(builder, name, age);
builder.Finish(person);
uint8_t *buf = builder.GetBufferPointer();
size_t size = builder.GetSize();
/* Теперь buf содержит сериализированные данные */
return 0;
}
Эти библиотеки предоставляют разные подходы и возможности для сериализации данных в C++, каждая из которых имеет свои преимущества и недостатки в зависимости от конкретных требований проекта.
Что такое сериализация?
Какие библиотеки знаете C++?
СЕРИАЛИЗАЦИЯ — процесс преобразования структуры данных или объекта в формат, пригодный для хранения или передачи (например, в файл или по сети).
Этот формат обычно представляет собой последовательность байтов, которую можно восстановить обратно в исходную структуру данных или объект позже.
ДЕСЕРЕАЛИЗАЦИЯ — процесс обратного восстановления данных из сериализованного формата.
Зачем нужна сериализация:
Хранение данных — позволяет сохранять объекты в файлах для последующего использования.
Передача данных — обмен данными между различными системами или приложениями, работающими на разных платформах.
Кэширование — сохранение промежуточных результатов вычислений для ускорения последующих запросов.
Отладка и мониторинг — запись состояний системы для анализа и диагностики.
Примеры библиотек для сериализации в C++:
Boost.Serialization — библиотека, входящая в состав Boost, которая предоставляет мощные средства для сериализации и десериализации объектов C++.
Поддерживает различные форматы, включая текстовые файлы, бинарные данные и архивы.
Пример использования:
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
class Person {
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & name;
ar & age;
}
public:
std::string name;
int age;
};
int main() {
Person person{"John", 30};
std::ofstream ofs("person.txt");
boost::archive::text_oarchive oa(ofs);
oa << person;
return 0;
}
Сereal — современная библиотека для сериализации в C++, которая поддерживает множество различных форматов, таких как JSON, XML, binary и другие.
Легко интегрируется с популярными контейнерами STL и пользовательскими типами.
Пример использования:
#include <cereal/archives/json.hpp>
#include <fstream>
struct Person {
std::string name;
int age;
template<class Archive>
void serialize(Archive & archive) {
archive(CEREAL_NVP(name), CEREAL_NVP(age));
}
};
int main() {
Person person{"Jane", 25};
std::ofstream os("person.json");
cereal::JSONOutputArchive oarchive(os);
oarchive(person);
return 0;
}
Google Protocol Buffers (Protobuf) — кросс-платформенная система сериализации структурированных данных, разработанная компанией Google.
Протобуферы обеспечивают компактное представление данных и высокую производительность.
Пример использования:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}
Затем этот .proto файл нужно скомпилировать в C++ код с помощью protoc компилятора.
Thrift (Apache Thrift) — фреймворк для создания высокопроизводительных сервисов и систем обмена сообщениями, который также включает поддержку сериализации.
Thrift генерирует код на основе определения интерфейса, написанного на специальном языке.
Пример использования:
namespace cpp example
struct Person {
1: required string name,
2: optional i32 age,
}
Затем этот .thrift файл нужно скомпилировать в C++ код с помощью thrift компилятора.
FlatBuffers — библиотека от Google, предназначенная для эффективной сериализации и десериализации структурированных данных.
Отличается тем, что данные хранятся в одном буфере, что позволяет быстро обращаться к ним без необходимости полной десериализации.
Пример использования:
#include "flatbuffers/flatbuffers.h"
#include "Person_generated.h"
int main() {
flatbuffers::FlatBufferBuilder builder;
auto name = builder.CreateString("Alice");
auto age = 20;
auto person = CreatePerson(builder, name, age);
builder.Finish(person);
uint8_t *buf = builder.GetBufferPointer();
size_t size = builder.GetSize();
/* Теперь buf содержит сериализированные данные */
return 0;
}
Эти библиотеки предоставляют разные подходы и возможности для сериализации данных в C++, каждая из которых имеет свои преимущества и недостатки в зависимости от конкретных требований проекта.
#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
Каждая из этих категорий имеет свою область применения и особенности, соответствующие требованиям конкретной среды эксплуатации.
Выбор ОС зависит от задач, которые необходимо решать, и характеристик оборудования, на котором она будет использоваться.
Что такое операционная система?
Какие существуют типы ОС по назначению?
Операционная система (ОС) — комплекс программ, обеспечивающий управление аппаратными ресурсами компьютера и предоставляющий пользователям и прикладным программам интерфейс взаимодействия с этими ресурсами.
ОС выполняет функции посредника между пользователем и оборудованием, обеспечивая удобство работы и эффективное использование ресурсов.
Основные задачи операционной системы:
— управление процессами (планирование задач);
— управление памятью (распределение оперативной и виртуальной памяти);
— управление устройствами ввода-вывода (драйверы устройств);
— управление файловой системой (организация хранения данных);
— обеспечение безопасности и защиты данных;
— предоставление 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 использует виртуальную память, позволяющую ОС работать с большим объемом данных, чем физически доступно в оперативной памяти.
При нехватке оперативной памяти часть данных переносится на жесткий диск (свопинг).
Основные составляющие и принципы работы ОС 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 представляет собой мощную и гибкую операционную систему, подходящую для самых разных задач благодаря своей модульности, открытости и широкому сообществу разработчиков.
Каждый файл и каталог имеют владельца, группу и набор разрешений, определяющих, кто может читать, записывать или исполнять данный файл.
Это обеспечивает высокий уровень безопасности системы.
Модульность — многие компоненты 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.
Она позволяет правильно скомпилировать и связать функции, используя нужное соглашение о вызове функций, что особенно важно при использовании внешних библиотек или создании библиотек, которые могут быть использованы в проектах на разных языках программирования.
Для чего нужен 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(), чтобы убедиться, что всё прошло успешно.
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 является важным инструментом для разработчиков и системных администраторов, работающих с безопасностью сетевых приложений и сервисов.
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
Аналоги 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++ не предоставляет встроенные криптографические функции, существует множество сторонних библиотек, которые можно использовать для решения подобных задач. Выбор конкретной библиотеки зависит от ваших потребностей и предпочтений.
Пример использования 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 для создания защищённых соединений.
Есть ли какие средства для работы с криптографией в 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 позволяет вам получить информацию о том, какой тип лежит в основе перечисления.
Как определить базовый тип лежащий в основе 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();
}
Случаи неопределенного поведения в С.
Неопределенное поведение (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.
— непустой исходный файл, не оканчивающийся на пустую строку (или оканчивающийся на обратный слеш);
— обратный слеш после которого стоит нечто отличное от перечня 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
Эти режимы позволяют разработчикам находить и исправлять ошибки до того, как они приведут к серьезным проблемам в продакшене.
Важно отметить — включение этих опций может увеличить время компиляции и выполнение программы, поэтому рекомендуется использовать их только в процессе разработки и тестирования.
Санитайзеры в программировании.
-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 (для построения графов вызовов функций)
Все перечисленные инструменты имеют свои особенности и область применения.
Выбор конкретного инструмента зависит от потребностей вашего проекта: хотите ли вы найти утечки памяти, улучшить производительность, обеспечить безопасность или просто придерживаться определённых стандартов кодирования.
Анализаторы кода для С и С++
Для ЯП 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.
Подопции предоставляют гибкость в настройке поведения санитайзеров и позволяют адаптировать их под требования проекта.
Подопции 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 битовые поля определяются внутри структур с указанием количества битов, занимаемых каждым полем:
Структура Flags содержит три битовых поля:
flag1 занимает 1 бит,
flag2 занимает 2 бита,
flag3 занимает 3 бита.
Поскольку каждый бит может принимать значения 0 или 1, битовые поля могут использоваться для хранения булевых значений или небольших целых чисел.
Особенности битовых полей в C:
— порядок размещения — стандарт C не определяет точный порядок размещения битовых полей в памяти.
Это означает, что разные компиляторы могут размещать их по-разному.
— размер полей — размер битового поля должен быть меньше или равен размеру базового типа данных (например, unsigned int).
— доступ к битовым полям — доступ к битовым полям осуществляется так же, как и к обычным членам структуры.
Пример использования битовых полей в C:
Битовые поля в C++.
В языке C++ битовые поля работают аналогичным образом, как и в C.
Основное отличие заключается в поддержке пространства имен и классов.
Особенности битовых полей в C++:
— размещение — так же, как и в C, порядок размещения битовых полей в памяти не определен стандартом.
— размер полей — размер битового поля должен быть меньше или равен размеру базового типа данных.
— доступ к битовым полям — доступ к битовым полям осуществляется так же, как и к обычным членам класса или структуры.
Битовые поля в C и C++ являются полезным средством для экономии памяти, особенно в системах с ограниченными ресурсами.
Однако стоит учитывать, что их использование может усложнить понимание и сопровождение кода, а также привести к проблемам совместимости между платформами и компиляторами.
Битовые поля в структурах в С и С++
Битовые поля в структурах позволяют экономить память, храня несколько логически независимых значений в одном байте или слове.
Битовые поля представляют собой часть структуры, которая может занимать меньше одного байта.
Это полезно, когда нужно упаковать много небольших значений в ограниченном пространстве памяти.
Битовые поля в 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:
Преимущества:
— простота использования для небольших проектов;
— широкая поддержка и документация;
— подходит для кросс-платформенной разработки.
Недостатки:
— сложность поддержки больших проектов;
— ограниченная функциональность по сравнению с более современными инструментами.
CMake — система генерации make-файлов и других сценариев сборки для различных платформ и компиляторов.
Вместо того чтобы писать конкретные инструкции для каждой целевой платформы, вы описываете проект в специальном языке CMake, а затем генерируете файлы сборки для нужной среды.
Пример файла CMakeLists.txt:
Преимущества:
— поддерживает множество целевых платформ и компиляторов;
— удобен для сложных проектов с большим количеством зависимостей;
— позволяет легко генерировать проекты для IDE, таких как Visual Studio, Xcode и др.
Недостатки:
— более сложный синтаксис по сравнению с Make;
— требует времени на освоение.
NINJA — инструмент для построения проектов, разработанный Google, не является системой управления проектами сам по себе, а скорее служит "исполнителем" задач, которые ему передаются другими системами, такими как CMake.
Ninja известен своей высокой скоростью выполнения задач.
Пример файла build.ninja:
Преимущества:
— очень высокая скорость сборки;
— легкий синтаксис и минималистичный подход;
— хорошо интегрируется с CMake.
Недостатки:
— не предназначен для самостоятельного описания проекта; требует внешнего инструмента вроде CMake.
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.
Важно учитывать особенности каждого инструмента, его возможности и ограничения, чтобы выбрать наиболее подходящий вариант для вашей команды и проекта.
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;
— сгенерируем случайное число в заданном диапазоне.
Пример кода:
Объяснение:
Заголовок <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)
Можно легко изменить код выше, чтобы использовать любое из этих распределений, просто заменив соответствующий класс распределения.
Генерация случайных чисел в С++.
Генерация случайных чисел в языке программирования 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)
Можно легко изменить код выше, чтобы использовать любое из этих распределений, просто заменив соответствующий класс распределения.