Библиотека C/C++ разработчика | cpp, boost, qt
20.8K subscribers
1.6K photos
44 videos
16 files
3.77K links
Все самое полезное для плюсовика и сишника в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/d6cd2932

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5bac324c8ba6dcaa1ad17
加入频道
🚀🕛 Сортировка конфигов для Make сборок

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

Все передают конфиги по-разному. Это один из религиозных аспектов в программировании микроконтроллеров.

1--Junior разработчики прописывают константы в каждом файле проекта или пихают всё в config.h, который потом вручную подключают #include(ом) во все *.с файлы,

2--Middle программисты передают конфиги через переменные окружения, которые определяют в скриптах сборки (Make, Cmake и т.п.).

3--Senior(ы) вообще передают конфиги через Device Tree и механизм Kconfig.

В статье не будут рассуждать как лучше и правильнее передавать конфиги в сборки. Разговор будет о том, как поступать, когда конфиги прописаны как переменные окружения в отдельном make файле по имени config.mk.

Читать статью

#почитать
#вопросы_с_собеседования

Что будет выведено на экран?


#include <iostream>

int a = 4;

int &f(int x){
a = a + x;
return a;
}

int main(void){
int t = 5;
std::cout << f(t) << std::endl;
f(t) = 20;
std::cout << f(t) << std::endl;
t = f(t);
std::cout << f(t) << std::endl;
}


В первом случае на печать выведется 9, потому что функция f принимает параметр t = 5, внутри функции к глобальной переменной a прибавляется 5, теперь a = 9, а f возвращает ссылку на неё и печатается значение a, то есть 9.

Далее неважно, что происходит внутри функции, важно, что возвращаемой ссылке на a присваивается 20, значит a = 20. Переменная t не поменяла своё значение, так как в функцию она передается по значению, а не по ссылке.

Затем опять вызываем f(5), при этом a = 20, a = 20 + 5, на печати увидим число 25.

Теперь присваиваем t значение a (в этот момент a = 25 + 5), значит, t станет равно 30.

И, наконец, последняя печать. Вызываем f(30), a = 30 + 30, и возвращается значение 60.
std::find_if

std::find_if — это стандартный алгоритм, предоставляемый библиотекой . Этот алгоритм предназначен для поиска первого элемента в заданном диапазоне, который удовлетворяет заданному условию, определенному предикатом.

Вот общий формат std::find_if:

#include

template
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);

first и last представляют диапазон элементов для поиска. first указывает на начало диапазона, а last указывает за его пределы.
p — это унарный предикат, то есть функция, принимающая один аргумент и возвращающая true, если элемент удовлетворяет условию, и false в противном случае.
std::find_if

std::find_if — это стандартный алгоритм, предоставляемый библиотекой <algorithm>. Этот алгоритм предназначен для поиска первого элемента в заданном диапазоне, который удовлетворяет заданному условию, определенному предикатом.

Вот общий формат std::find_if:

#include <algorithm>

template<class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);


first и last представляют диапазон элементов для поиска. first указывает на начало диапазона, а last указывает за его пределы.
p — это унарный предикат, то есть функция, принимающая один аргумент и возвращающая true, если элемент удовлетворяет условию, и false в противном случае.
Как получить размер файла в байтах?

В C++17 была добавлена библиотека filesystem, которая упрощает работу с файловой системой

#include <filesystem>

int main()
{
std::uintmax_t size = std::filesystem::file_size("file.txt");
}


❗️Стоит учитывать, что если файл был открыт не только вами, то размер может быть изменён извне
🍔 Отладочные макросы

Отладочные макросы в C++ используются для упрощения процесса отладки и диагностики программного кода

Основные отладочные макросы включают assert, static_assert и пользовательские макросы

🍓 assert

Макрос assert определён в заголовочном файле <cassert> и используется для проверки логических выражений во время выполнения программы. Если выражение вернёт false, assert завершает выполнение программы и выводит сообщение об ошибке
#include <cassert>

void test(int x) {
assert(x > 0 && "x must be positive");
// остальной код функции
}

int main() {
test(5); // проходит проверку
test(-3); // приводит к ошибке во время выполнения
return 0;
}


🍒 static_assert

static_assert введён в C++11 и позволяет проверять условия на этапе компиляции. Это особенно полезно для проверки условий, которые должны выполняться всегда, независимо от состояния программы во время выполнения
#include <type_traits>

template <typename T>
void check() {
static_assert(std::is_integral<T>::value, "T must be an integral type");
}

int main() {
check<int>(); // проходит проверку
check<float>(); // ошибка компиляции: T must be an integral type
return 0;
}


🫐 Пользовательские отладочные макросы

Вы также можете определять собственные макросы для отладки, которые помогут вам выводить дополнительную информацию или выполнять специфические проверки

#include <iostream>

#define DEBUG

#ifdef DEBUG
#define DEBUG_PRINT(x) std::cout << x << std::endl
#else
#define DEBUG_PRINT(x)
#endif

int main() {
int value = 42;
DEBUG_PRINT("Value: " << value);
return 0;
}
Forwarded from Антон Клеймёнов
😎 Как использовать модули в C++?

D C++ 20 появилась новая конструкция языка под названием модули. Ускорение компиляции и упрощение управление зависимостями можно назвать основными причинами введения их в стандарт.

❗️ Для того чтобы воспользоваться модульной магией нужно добавить export module вначале файла и тогда он станет модулем

// Файл math.ixx
export module math;

export int add(int a, int b) {
return a + b;
}

export int subtract(int a, int b) {
return a - b;
}


❗️ Подключается же модуль с помощью ключевого слова import

// main.cpp
import math; // Подключаем модуль

#include <iostream>

int main() {
std::cout << "5 + 3 = " << add(5, 3) << std::endl;
std::cout << "5 - 3 = " << subtract(5, 3) << std::endl;
return 0;
}
std::decay_t — один из самых полезных type traits в C++. Он имитирует процесс передачи параметра по значению, «разрушая» исходный тип.

🔄 Что именно делает decay_t?

• Убирает cv-квалификаторы
• Превращает ссылки в соответствующие типы без ссылок
• Преобразует массивы в указатели
• Преобразует функции в указатели на функции

💻 Пример:
#include <type_traits>
#include <iostream>

int main() {
// const int& -> int
static_assert(std::is_same_v<std::decay_t<const int&>, int>);

// int[10] -> int*
static_assert(std::is_same_v<std::decay_t<int[10]>, int*>);

// void(int) -> void(*)(int)
static_assert(std::is_same_v<std::decay_t<void(int)>, void(*)(int)>);

std::cout << "All assertions passed!" << std::endl;
}


🚀 Где это используется?

• В шаблонном программировании для упрощения работы с типами
• В std::make_shared и std::make_unique для определения типа создаваемого объекта
• При написании обобщенного кода, где нужна правильная дедукция типов

🔍 И да, название «decay» («разрушение») действительно отражает суть — тип «разрушается» до базового представления!
📚 Загадочная библиотека setjmp.h — неочевидный инструмент для управления потоком выполнения


Библиотека setjmp.h предоставляет два необычных макроса:

setjmp — сохраняет текущее состояние программы (регистры, стек) в буфер jmp_buf

longjmp — «откатывает» выполнение к сохранённому состоянию, как прыжок во времени



#include <stdio.h>
#include <setjmp.h>

jmp_buf jump_buffer;

void risky_function() {
printf("Готовимся к прыжку...\n");
longjmp(jump_buffer, 42); // Прыжок обратно в setjmp!
}

int main() {
int ret = setjmp(jump_buffer);
if (ret == 0) {
printf("Первая инициализация...\n");
risky_function();
} else {
printf("Вернулись с кодом: %d\n", ret); // Выведет 42!
}
return 0;
}


⚠️ Осторожно!

• Не заменяет исключения — нет вызова деструкторов (как в C++)
• Опасность утечек — если между setjmp и longjmp выделялась память, она не освободится
• Портит стек — может сломать логику функций

🛠 Где может пригодиться?

• Обработка критических ошибок (а-ля «аварийный выход»)
• Код для встраиваемых систем, где нужно быстро восстановить состояние
• Нестандартные хаки (но лучше так не делать 😈)

Библиотека C/C++ разработчика
🔥 Бьярн Страуструп о будущем C++, рисках ИИ и сложности замены языка

Создатель языка C++ Бьярн Страуструп поделился своим видением «C++ 21-го века» на конференции Qt World Summit в Мюнхене.

По его словам, современный C++ — это не просто набор новых функций, а более целостный, эффективный и безопасный язык.

Страуструп рекомендует:

• Использовать более прямые конструкции вместо традиционных переменных цикла
• Применять обобщенное программирование с автоматическим выводом типов
• Никогда не использовать «сырые указатели» как ресурсные дескрипторы
• Заменить устаревшие #include на современные import

Страуструп выразил обеспокоенность влиянием ИИ на программирование: «ИИ склоняет людей к устаревшим подходам, а программисты теряют способность выявлять проблемы».

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

Библиотека C/C++ разработчика