this->notes.
4.54K subscribers
35 photos
1 file
371 links
О разработке, архитектуре и C++.

Tags: #common, #cpp, #highload и другие можно найти поиском.
Задачки: #poll.
Мои публикации: #pub.
Автор и предложка: @vanyakhodor.
GitHub: dasfex.
Download Telegram
#cpp

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.
🔥216
#cpp

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.
👍291
#cpp

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.
https://godbolt.org/z/8G1soa8T1

Теперь срочно требуйте оффер х3 от вашего текущего дохода, ведь собеседующий почти наверняка этого не знает.

@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍18🔥85🤯2😭1