#cpp
The worst programming language of all time.
Или нет?
Возможно вам уже попадалось видео: youtube.com/watch?v=7fGB-hjc2Gc, рассказывающее, почему C++ — самый ужасный язык программирования. Разберём автором рассказанное.
https://github.com/dasfex/articles/blob/trunk/the_worst_programming_language_of_all_time.md
[Пост появился раньше на пару дней на] Patreon и Boosty.
Спасибо Artyom Garkavy за поддержку.
The worst programming language of all time.
Или нет?
Возможно вам уже попадалось видео: youtube.com/watch?v=7fGB-hjc2Gc, рассказывающее, почему C++ — самый ужасный язык программирования. Разберём автором рассказанное.
https://github.com/dasfex/articles/blob/trunk/the_worst_programming_language_of_all_time.md
[Пост появился раньше на пару дней на] Patreon и Boosty.
Спасибо Artyom Garkavy за поддержку.
❤22👎9😁8👍3❤🔥2🔥2🐳1
#books #cpp
C++17 - Iterating Problems.
Автор поставил себе задачу исследовать возможности C++17 (да, сегодня это уже немного outdated увлечение).
Делает он это с помощью задач с hackerrank. По своей сути они простые, но ведь любую задачу можно бесконечно усложнить, чем автор и занимается.
Фичи языка, которые рассматриваются в книге, покрывают (но не ограничиваются): итераторы, type traits, SFINAE, вычисления на компиляции, fold expressions, std::variant, std::any.
Понятно, что код в итоге смотрится ужасно. Вот, например, для Hello world:
Он небольшой и понимаемый, но если нужно будет такое апрувать, я настойчиво откажусь.
Причём это самая простая задача. С самым сжатым кодом. Дальше начинается полный разнос с нечитаемыми решениями.
Но!
Книга может научить важным вещам, которые вам понадобятся при проектировании общих решений/алгоритмов. Подобные задачи всегда связаны с большим количеством крайних случаев и потенциальных ошибок. Автор хоть и не получает всегда идеальное решение (так как задача — поюзать как можно больше фичей), но причины тех или иных решений объясняет. Возможно, не все из них имеют отношение к реальным задачам. Но важно уловить паттерн и ход мысли.
Из минусов: с какого-то момента книга становится монотонной. Ну штош.
3 итератора из 7.
Спасибо Artyom Garkavy и niki4smirn.
Patreon, Boosty.
C++17 - Iterating Problems.
Я бы сказал, что это не книга, а книжка. Возможно мегабуклет. Просто из-за размера. Но пусть будет книга.
Автор поставил себе задачу исследовать возможности C++17 (да, сегодня это уже немного outdated увлечение).
Делает он это с помощью задач с hackerrank. По своей сути они простые, но ведь любую задачу можно бесконечно усложнить, чем автор и занимается.
Фичи языка, которые рассматриваются в книге, покрывают (но не ограничиваются): итераторы, type traits, SFINAE, вычисления на компиляции, fold expressions, std::variant, std::any.
Понятно, что код в итоге смотрится ужасно. Вот, например, для Hello world:
template <typename I, typename O>
auto
hello_world(I first, I last, O out) {
return std::copy(first, last, out);
}
int
main(int, char *[]) {
auto hello = std::array{"Hello", "World!"};
auto out = os_iterator<std::string>{std::cout, ", "};
hello_world(hello.begin(), hello.end(), out);
return 0;
}
Он небольшой и понимаемый, но если нужно будет такое апрувать, я настойчиво откажусь.
Причём это самая простая задача. С самым сжатым кодом. Дальше начинается полный разнос с нечитаемыми решениями.
Но!
Книга может научить важным вещам, которые вам понадобятся при проектировании общих решений/алгоритмов. Подобные задачи всегда связаны с большим количеством крайних случаев и потенциальных ошибок. Автор хоть и не получает всегда идеальное решение (так как задача — поюзать как можно больше фичей), но причины тех или иных решений объясняет. Возможно, не все из них имеют отношение к реальным задачам. Но важно уловить паттерн и ход мысли.
Из минусов: с какого-то момента книга становится монотонной. Ну штош.
3 итератора из 7.
Спасибо Artyom Garkavy и niki4smirn.
Patreon, Boosty.
✍19👍7❤3💩2🔥1
#cpp
Принёс доклады с C++ Russia 2025.
В хронологическом порядке.
0. LLVM MemProf и методы профилирования памяти.
Алексей Веселовский.
Крутой доклад про профилирование памяти. Что важно, осознаваемый на 1.5х без напряга, но при этом всё ещё сложноватый.
1. [Не]очевидные оптимизации и паттерны из userver. Антон Полухин.
Антон продолжал серию докладов про всякие приколюхи из userver.
Обычно (и в этот раз, и, я уверен, в в конференции этого года) это рассказ про несколько отдельных улучшений/фиксов/оптимизаций из userver. Глубоко в теорию в них не закапываемся. Скорее подразумевается наличие экспертизы.
Интересно как точка расширения сознания, чтобы потом пойти чего-то ещё поизучать.
2. Как компиляторы на основе LLVM моделируют неопределенное поведение и извлекают из него пользу. Макс Казанцев.
Доклад про некоторую внутрянку работы с UB в компиляторах, как они детектят проблемные случаи и что делают с этой информацией. Имхо довольно свежо.
3. Замеряем производительность для высоконагруженных проектов с Google Benchmark. Савва Лебедев.
Введение в gbench. Что важно, там и базовое что-то есть, и что-то, что может вам пригодиться, если вы вроде какие-то бенчмарки писали, но в перф глубоко не погружены. Для становления perf-person.
4. Уроки кодогенерации JSON Schema. Василий Куликов.
Вася — один из основных контрибьюторов userver.
Снаружи (вне Яндекса), в отличие от опенсорсной версии фреймворка, userver изначально имел кодген, который по OpenAPI спецификации позволял генерить готовый код для ручек, внутренних классов и работы с ними. Не нужно было раскладывать JSON в плюсовую структуру самому, например.
Вася рассказывал про новую кодогенерацию в фреймворке.
Я так понимаю, что в итоге именно она в опенсорсе и появилась.
5. Как мы работаем над производительностью мобильного приложения в 2ГИС. Дмитрий Ястребков.
Рассказ скорее фановый, про процессы, похвалиться. Скорее для хайлоада имхо.
Но круто, что чуваки болеют за перф и системно что-то с ним делают. К сожалению, это не везде так. И к сожалению, иногда это напрямую задевает пользователей.
Когда я на конфе слушал доклад, меня что-то там смутило. Что-то связанное с измерением метрик или интерпретацией данных.
За год я забыл, к сожалению.
6. Лицензии ПО: теория, которая спасает от финансовых катастроф. Ольга Кузмичева, Георгий Панюшкин.
Ребята рассказывали про то, что и заявлено в заголовке.
Я в теме нуб. Было интересно послушать про что-то важное для сферы в целом, но какое-то тёмное непонятное юридическое.
7. Ржавеющие плюсы: как внедрять современные проверки С++ в промышленных масштабах. Винсент Амбо.
Винсент рассказывал про харденинг и его внедрение в Яндексе.
Плюсы и безопасность это топики тяжёлые (если вместе обсуждать), так что всегда полезно ещё что-то сделать в этом месте.
8. Как заставить шаблоны компилироваться быстро и выглядеть опрятно. Павел Сухов.
Пашу вы должны уже знать.
Меня тоже (я рядом стоял).
Паша рассказывает про проблемы компиляции шаблонов, про перф этого всего дела, и про то, как выглядеть опрятно (это отдельный вопрос).
9. [не доклад, а болталка] Чему C++ может научиться? Антон Полухин. Павел Новиков.
Люблю послушать некоторую внутрянку комитета по стандартизации. Тут Антон как раз рассказал пару небольших историй. Зашло.
.
Я выступал на offline only активности с лайтнингом. Рассказывал про оптимизацию разработки. Это была вариация этого доклада с некоторым уходом в сторону плюсов.
Принёс доклады с C++ Russia 2025.
В хронологическом порядке.
0. LLVM MemProf и методы профилирования памяти.
Алексей Веселовский.
Крутой доклад про профилирование памяти. Что важно, осознаваемый на 1.5х без напряга, но при этом всё ещё сложноватый.
1. [Не]очевидные оптимизации и паттерны из userver. Антон Полухин.
Антон продолжал серию докладов про всякие приколюхи из userver.
Обычно (и в этот раз, и, я уверен, в в конференции этого года) это рассказ про несколько отдельных улучшений/фиксов/оптимизаций из userver. Глубоко в теорию в них не закапываемся. Скорее подразумевается наличие экспертизы.
Интересно как точка расширения сознания, чтобы потом пойти чего-то ещё поизучать.
На youtube есть смешной комментарий:
> ты ему слово, а он тебе трюки из userver
2. Как компиляторы на основе LLVM моделируют неопределенное поведение и извлекают из него пользу. Макс Казанцев.
Доклад про некоторую внутрянку работы с UB в компиляторах, как они детектят проблемные случаи и что делают с этой информацией. Имхо довольно свежо.
3. Замеряем производительность для высоконагруженных проектов с Google Benchmark. Савва Лебедев.
Введение в gbench. Что важно, там и базовое что-то есть, и что-то, что может вам пригодиться, если вы вроде какие-то бенчмарки писали, но в перф глубоко не погружены. Для становления perf-person.
4. Уроки кодогенерации JSON Schema. Василий Куликов.
Вася — один из основных контрибьюторов userver.
Снаружи (вне Яндекса), в отличие от опенсорсной версии фреймворка, userver изначально имел кодген, который по OpenAPI спецификации позволял генерить готовый код для ручек, внутренних классов и работы с ними. Не нужно было раскладывать JSON в плюсовую структуру самому, например.
Вася рассказывал про новую кодогенерацию в фреймворке.
Я так понимаю, что в итоге именно она в опенсорсе и появилась.
5. Как мы работаем над производительностью мобильного приложения в 2ГИС. Дмитрий Ястребков.
Рассказ скорее фановый, про процессы, похвалиться. Скорее для хайлоада имхо.
Но круто, что чуваки болеют за перф и системно что-то с ним делают. К сожалению, это не везде так. И к сожалению, иногда это напрямую задевает пользователей.
Когда я на конфе слушал доклад, меня что-то там смутило. Что-то связанное с измерением метрик или интерпретацией данных.
За год я забыл, к сожалению.
6. Лицензии ПО: теория, которая спасает от финансовых катастроф. Ольга Кузмичева, Георгий Панюшкин.
Ребята рассказывали про то, что и заявлено в заголовке.
Я в теме нуб. Было интересно послушать про что-то важное для сферы в целом, но какое-то тёмное непонятное юридическое.
7. Ржавеющие плюсы: как внедрять современные проверки С++ в промышленных масштабах. Винсент Амбо.
Винсент рассказывал про харденинг и его внедрение в Яндексе.
Плюсы и безопасность это топики тяжёлые (если вместе обсуждать), так что всегда полезно ещё что-то сделать в этом месте.
8. Как заставить шаблоны компилироваться быстро и выглядеть опрятно. Павел Сухов.
Пашу вы должны уже знать.
Меня тоже (я рядом стоял).
Паша рассказывает про проблемы компиляции шаблонов, про перф этого всего дела, и про то, как выглядеть опрятно (это отдельный вопрос).
9. [не доклад, а болталка] Чему C++ может научиться? Антон Полухин. Павел Новиков.
Люблю послушать некоторую внутрянку комитета по стандартизации. Тут Антон как раз рассказал пару небольших историй. Зашло.
.
Я выступал на offline only активности с лайтнингом. Рассказывал про оптимизацию разработки. Это была вариация этого доклада с некоторым уходом в сторону плюсов.
👍14❤3🔥2👏1
#cpp
Поток (англ. flux)
https://github.com/dasfex/articles/blob/trunk/flux.md
Как обычно, на том же Patreon или Boosty пост был доступен раньше.
Спасибо Artyom Garkavy и niki4smirn.
Поток (англ. flux)
https://github.com/dasfex/articles/blob/trunk/flux.md
Как обычно, на том же Patreon или Boosty пост был доступен раньше.
Спасибо Artyom Garkavy и niki4smirn.
👍9❤4🤮2
#cpp
Day 1.
Думаю, все вы знаете, что
Инклудить вы можете что угодно. Хоть txt, хоть бинарный файл. Препроцессору на это всё равно. Главное, чтобы содержимое после препроцессинга было валидно.
Можно хоть так:
и потом
Порядок инклудов может значимо менять поведение в программе. Вот вам пример от Паши: https://xn--r1a.website/cpp_durka/49
Инклуды могут быть с
Когда-то препроцессор не умел добавлять пустую строку после инклудов, потому обязательно было иметь пустую строку в конце вашего файла. Сейчас можно и без этого, но душе уже не прикажешь...
Ну и всегда можно воспользоваться инструментом неправильно. Случайно или специально. Вспомним The Grand C++ Error Explosion Competition.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 1.
#include Думаю, все вы знаете, что
#include просто вставляет весь код в файл, в котором он расположен. Из-за этого даже простой Hello world с использованием std::cout разрастается до десятков-сотен тысяч строк (хотя сам хедер может быть маленький, он транзитивно тянет много других зависимостей). Собсна поэтому инклуды не очень любят: легко засрать ваш проект и получить большое время компиляции. Отсюда и появляются штуки вроде forward declaration, pimpl, precompiled headers, include-what-you-use и модули. Инклудить вы можете что угодно. Хоть txt, хоть бинарный файл. Препроцессору на это всё равно. Главное, чтобы содержимое после препроцессинга было валидно.
Можно хоть так:
#include "/dev/stdin"и потом
echo 'int x = 42;' | g++ main.cppПорядок инклудов может значимо менять поведение в программе. Вот вам пример от Паши: https://xn--r1a.website/cpp_durka/49
Инклуды могут быть с
<> и с "". Вариант подключения влияет на то, где хедеры ищутся. Когда-то препроцессор не умел добавлять пустую строку после инклудов, потому обязательно было иметь пустую строку в конце вашего файла. Сейчас можно и без этого, но душе уже не прикажешь...
Ну и всегда можно воспользоваться инструментом неправильно. Случайно или специально. Вспомним The Grand C++ Error Explosion Competition.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
🔥33👍8❤6🍌3💩2
#cpp
Day 2.
Так как
Защищаться от подобной ситуации нам помогают include guards (и pragma, но про неё не сегодня). Пишем в начале файла
Какие могут быть проблемы?
Если один и тот же GUARD используется в нескольких файлах, то один из них просто молча не подключится. Удачи дебагать!
Сейчас IDE (по крайней мере те, с которыми я работал) успешно генерируют длинное название, связанное с именем файла. Но не всегда успешно меняют имена guards при переименовании файла.
Есть ещё мнение, что include guards медленные. Хотя обычно, если у вас вид канонический, как в примере выше, то компиляторы способны запомнить, что файл уже был прочитан, и не тратить время на повторные операции.
Но если у вас какой-то специфический случай (начинаете вставлять код до include guards или после), то уже уверенными быть не стоит.
Исходя из того, как работают макросы и на что опираются guards, получается, что легко можно сломать инклуд хедера, если где-то определить
Вот ещё один пример, когда порядок хедеров может на что-то влиять.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 2.
Так как
#include просто вставляет код файла, приходится учитывать возможности, что один и тот же хедер притянется несколько раз. А это приводит к повторному объявлению ваших классов, функций, переменных и всего остального. Защищаться от подобной ситуации нам помогают include guards (и pragma, но про неё не сегодня). Пишем в начале файла
#ifndef GUARD_H
#define GUARD_H
#endif // GUARD_H
Какие могут быть проблемы?
Если один и тот же GUARD используется в нескольких файлах, то один из них просто молча не подключится. Удачи дебагать!
Сейчас IDE (по крайней мере те, с которыми я работал) успешно генерируют длинное название, связанное с именем файла. Но не всегда успешно меняют имена guards при переименовании файла.
Есть ещё мнение, что include guards медленные. Хотя обычно, если у вас вид канонический, как в примере выше, то компиляторы способны запомнить, что файл уже был прочитан, и не тратить время на повторные операции.
Но если у вас какой-то специфический случай (начинаете вставлять код до include guards или после), то уже уверенными быть не стоит.
Исходя из того, как работают макросы и на что опираются guards, получается, что легко можно сломать инклуд хедера, если где-то определить
#define:
#define GUARD_H
#include "some.h"
Вот ещё один пример, когда порядок хедеров может на что-то влиять.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍18💩3🔥2❤1⚡1🗿1
#cpp
Day 3.
Другой способ быть уверенным, что хедер включится только единожды:
Важно помнить, что это не стандартное решение, а универсальное расширение, которое реализуется де-факто всеми компиляторами.
• inode
• канонический path
• какой-то hash
• и другие варианты.
Из-за чего в сложных специфических системах может вполне себе сломаться. И вы получите один и тот же файл дважды. Удачи дебагать!
Аналогично могут быть проблемы в распределённых build-системах.
Иногда вы хотите, чтобы один файл инклудился дважды. Тогда
В некоторых сферах
Можно вообще в один файл совать и
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 3.
Другой способ быть уверенным, что хедер включится только единожды:
#pragma once. Важно помнить, что это не стандартное решение, а универсальное расширение, которое реализуется де-факто всеми компиляторами.
#pragma once хорошо оптимизируется (фактически). С ней даже чуть проще, так как она просто влияет на файл, в котором находится, когда include guards только на то, что внутри своего скоупа. #pragma once обычно работает через какой-то признак, помогающий понять, что файл — один и тот же. Из вариантов могут быть:• inode
• канонический path
• какой-то hash
• и другие варианты.
Из-за чего в сложных специфических системах может вполне себе сломаться. И вы получите один и тот же файл дважды. Удачи дебагать!
Аналогично могут быть проблемы в распределённых build-системах.
Иногда вы хотите, чтобы один файл инклудился дважды. Тогда
#pragma once вам не подходит. В некоторых сферах
#include guards выбирают просто за надёжность и стабильность, так как они зависят исключительно от кода, а не ещё каких-то посторонних вещей. Можно вообще в один файл совать и
#pragma once, и include guards. Чтобы спокойнее было.@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍19❤4💩2
#cpp
Day 4.
Макросы просто подменяют текст. Вот прям втупую. Но мы часто про это забываем, потому часто пишем их неправильно.
Паша @cppdurka Сухов говорил, что когда-то видел какой-то гайд на 18 страниц, как правильно писать макросы. Видел и потерял. А теперь жалеет об этом.
Я бы тоже хотел почитать. Скиньте, если знаете про такой!
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 4.
Макросы просто подменяют текст. Вот прям втупую. Но мы часто про это забываем, потому часто пишем их неправильно.
Паша @cppdurka Сухов говорил, что когда-то видел какой-то гайд на 18 страниц, как правильно писать макросы. Видел и потерял. А теперь жалеет об этом.
Я бы тоже хотел почитать. Скиньте, если знаете про такой!
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍15💩6😁3🫡1
#cpp
Day 5.
И код можно скомпилировать с
Или вы хотите написать разную логику для 32-битной и 64-битных систем:
Или вы хотите использовать новый стандарт, если он доступен, и не использовать, если есть своя поделка:
Хотя правильнее было бы проверять не на стандарт, а на доступность фичи/инклуда/атрибута, так как стандарт может быть новым, а STL старой. А некоторые фичи могут бекпортить.
Значения
Кто-то мне рассказывал байку, что MSVC много лет врал про значение
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 5.
#ifndef в include guards на самом деле #if !defined(...). Есть ещё #ifdef (#if defined(...)). Сам #if тоже есть. Можете намутить себе условной компиляции по самые колени. Например, может у вас есть какая-то дебажная сборка с большим кол-вом логов:
#ifdef DEBUG
printf("debug log");
#endif
И код можно скомпилировать с
-DDEBUG.Или вы хотите написать разную логику для 32-битной и 64-битных систем:
#if !(defined __LP64__ || defined __LLP64__) || defined _WIN32 && !defined _WIN64
// code for a 32-bit system
#else
// code for a 64-bit system
#endif
Или вы хотите использовать новый стандарт, если он доступен, и не использовать, если есть своя поделка:
#if __cplusplus >= 202002L
#include <span>
#else
#include "my_span.hpp"
#endif
Хотя правильнее было бы проверять не на стандарт, а на доступность фичи/инклуда/атрибута, так как стандарт может быть новым, а STL старой. А некоторые фичи могут бекпортить.
#if __cpp_lib_span
#if __has_include(<format>)
#if __has_cpp_attribute(likely)
#define LIKELY [[likely]]
#else
#define LIKELY
#endif
Значения
__cpp_* макросов это кстати дата принятия фичи WG21. Например, для __cpp_constexpr это 202211L (ноябрь 2022). Для того же constexpr можно узнавать его версию и соответственно набор возможностей, которые вы можете использовать, так как от стандарта к стандарту он сильно умощнялся. Кто-то мне рассказывал байку, что MSVC много лет врал про значение
__cplusplus (всегда возвращал 199711L, даже для C++17), потому писали вот так:
#if defined(_MSVC_LANG)
#define CPP_VER _MSVC_LANG
#else
#define CPP_VER __cplusplus
#endif
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍26🔥2💩2❤1
#cpp
Day 6.
Предположим, мы хотим написать макрос для возведения значения или переменной в квадрат:
В зависимости от способа использования, вы можете не получить или получить проблемы. В таком коде:
мы на самом деле получим
Что не совсем то, что вы ожидали.
Для надёжности лучше завернуть аргументы в скобки:
Но этого тоже может иногда не хватать:
Получим:
Что тоже не то, что мы ожидали. Так что адекватный макрос должен как минимум завернуть в скобки каждый отдельный аргумент + завернуть всё выражение:
Как максимум, ваш
Так что прям совсем идеально было бы сохранить результат внутри макроса и переиспользовать его. Но я не знаю, как это написать, чтобы было полностью эквивалентно функции.
Мб пора начать сворачивать с макродорожки на что-то более современное......
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 6.
Предположим, мы хотим написать макрос для возведения значения или переменной в квадрат:
#define SQR(x) x * x
В зависимости от способа использования, вы можете не получить или получить проблемы. В таком коде:
int a = SQR(1 + 2);
мы на самом деле получим
int a = 1 + 2 * 1 + 2;
Что не совсем то, что вы ожидали.
Для надёжности лучше завернуть аргументы в скобки:
#define SQR(x) (x) * (x)
Но этого тоже может иногда не хватать:
#define INC(x) (x) + 1
int a = 10 / INC(1 + 1);
Получим:
int a = 10 / (1 + 1) + 1;
Что тоже не то, что мы ожидали. Так что адекватный макрос должен как минимум завернуть в скобки каждый отдельный аргумент + завернуть всё выражение:
#define SQR(x) ((x) * (x))
Как максимум, ваш
x может быть вообще-то функцией с сайд-эффектом:
int x = SQR(GetValueFromDbAndPostToKafka());
Так что прям совсем идеально было бы сохранить результат внутри макроса и переиспользовать его. Но я не знаю, как это написать, чтобы было полностью эквивалентно функции.
Мб пора начать сворачивать с макродорожки на что-то более современное......
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
🔥22❤6
#cpp
Day 7.
Вчера мы писали макросы, которые заменяли собой один statement. А что, если я хочу что-то более сложное?
Обопрусь на пример от Паши (https://xn--r1a.website/cpp_durka/23): напишем макрос для инкремента двух переменных.
Тут мы умные. Сразу взяли выражения в скобки. Не поставили в конце
Но если мы чуть-чуть отступим от глупого использования:
мы получим
Или ещё пример:
Тут
Канонический способ такое исправить:
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 7.
Вчера мы писали макросы, которые заменяли собой один statement. А что, если я хочу что-то более сложное?
Обопрусь на пример от Паши (https://xn--r1a.website/cpp_durka/23): напишем макрос для инкремента двух переменных.
#define INCREMENT_BOTH(x, y) (x)++; (y)++
Тут мы умные. Сразу взяли выражения в скобки. Не поставили в конце
; , чтобы обязать пользователя её поставить самому (для консистентности кода). Но если мы чуть-чуть отступим от глупого использования:
if (condition)
INCREMENT_BOTH(a, b);
мы получим
if (condition)
(a)++; (b)++;
b инкрементится вне зависимости от условия. Или ещё пример:
#define MACRO(condition, x) if (condition) std::cout << (x)
if (flag)
MACRO(flag2, 5);
else
std::cout << 10;
Тут
else вдруг начинает относиться к if из макроса, а не изначальному, что очевидно баг. Канонический способ такое исправить:
#define INCREMENT_BOTH(x, y) \
do { \
(x)++; \
(y)++; \
} while (0)
#define MACRO(condition, x) \
do { \
if (condition) { \
std::cout << (x);\
} \
} while (0)
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍31❤1
#cpp
Day 8.
В C тоже есть массивы. И работягам тоже хочется знать, сколько в этих массивах элементов. Стандартного решения у ребят там нет, но есть общий подход, перетекающий из кодовой базы в кодовую базу. Зовётся
Выглядит так:
Тут мы полагаемся на
Так что
На собесах могут спрашивать вопросы с подвохом вида:
Конечно, вы на такое не попадётесь и скажете 10, ведь
Конечно нет!
Если ваш аргумент — Variable Length Array, то sizeof придётся вычислить аргумент. Мы можем запруфать это через наличие сайдэффекта:
Увидим called в output.https://godbolt.org/z/8G1soa8T1
Теперь срочно требуйте оффер х3 от вашего текущего дохода, ведь собеседующий почти наверняка этого не знает.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 8.
В C тоже есть массивы. И работягам тоже хочется знать, сколько в этих массивах элементов. Стандартного решения у ребят там нет, но есть общий подход, перетекающий из кодовой базы в кодовую базу. Зовётся
ARRAY_LENGTH/ARRAY_LEN/ARRAY_SIZE/COUNTOF/...Выглядит так:
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
Тут мы полагаемся на
sizeof, который, согласно стандарту C99 (моя вольная интерпретация):sizeofвозвращает размер операнда (в байтах). Размер зависит от типа операнда. Результат —int. Обычно результат не evaluated и является integer constant.
Another use of the sizeof operator is to compute the number of elements in an array:
sizeof array / sizeof array[0]
Так что
sizeof(x) вернёт кол-во байт типа массива (если x — массив int[3], то можем получить (в зависимости от системы) 12). sizeof((x)[0]) вернёт размер типа одного элемента (в нашем случае 4). Вот и получаем 3.На собесах могут спрашивать вопросы с подвохом вида:
int x = 10;
sizeof(x++);
std::cout << x; // result?
Конечно, вы на такое не попадётесь и скажете 10, ведь
sizeof интересует тип. Он не evaluatит свой аргумент. Но всегда ли это так? Если ваш аргумент — Variable Length Array, то sizeof придётся вычислить аргумент. Мы можем запруфать это через наличие сайдэффекта:
int f() {
printf("called\n");
return 10;
}
int main() {
sizeof(int[f()]);
}
Увидим called в output.
Теперь срочно требуйте оффер х3 от вашего текущего дохода, ведь собеседующий почти наверняка этого не знает.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍20🔥9❤6🤯3😭2
#cpp
Day 9.
До сегодняшнего дня мы были где-то на уровне 1. Сегодня делаем шаг на следующую ступеньку (вниз или вверх, это как посмотреть).
Подстановка макросов (expansion) не являются рекурсивной.
Выстрелить себе в ногу становиться чуть сложнее. Или проще. Это опять как посмотреть.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 9.
До сегодняшнего дня мы были где-то на уровне 1. Сегодня делаем шаг на следующую ступеньку (вниз или вверх, это как посмотреть).
Подстановка макросов (expansion) не являются рекурсивной.
#define A(x) A(x x)
A(x) // A(x x)
#define B(x) C(x x)
#define C(x) B(x x)
B(x) // B(x x x x)
Выстрелить себе в ногу становиться чуть сложнее. Или проще. Это опять как посмотреть.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
❤10👍5🔥1