#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.
👍22🔥9❤7🤯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.
❤14👍10🔥2
#cpp
Day 10.
Когда вы работаете с макросами, вам может пригодиться stringification operator.
Он позволяет превратить аргумент макроса в строку:
Причём аргумент в таком случае не expandится:
Если хотите раскрыть, нужен ещё один уровень:
Так что некоторые разные входные данные могут давать одинаковый результат. Надо быть осторожными.
Вы можете использовать
Эта же фича используется в
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 10.
Когда вы работаете с макросами, вам может пригодиться stringification operator.
#define STR(x) #x
Он позволяет превратить аргумент макроса в строку:
STR(123 foo real) // "123 foo real"
Причём аргумент в таком случае не expandится:
#define FOO 123
#define STR(x) #x
STR(FOO) // "FOO"
Если хотите раскрыть, нужен ещё один уровень:
#define STR2(x) #x
#define STR(x) STR2(x)
STR(FOO) // "123"
# почти сохраняет исходный текст (может поудалять лишние пробелы):
STR( a + b ) // "a + b"
Так что некоторые разные входные данные могут давать одинаковый результат. Надо быть осторожными.
Вы можете использовать
# для дебажных утилиток:
#define PRINT(expr) \
std::cout << #expr << " = " << (expr) << '\n';
PRINT(x + y) // x + y = 12
Эта же фича используется в
assert (вы видите упавшее условие в ошибке).@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍27❤5🔥3❤🔥2
#cpp
Day 11.
Используется в макросах для склеивания двух токенов (на этапе препроцессинга конечно же).
Склеиваются именно токены. После препроцессинга должен получиться валидный токен:
Используется для генерации чего угодно. Часто думают только про имена функций/переменных/классов, но можно и для операторов, ключевых слов, литералы.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 11.
## — token pasting operator или token concatenation operator.Используется в макросах для склеивания двух токенов (на этапе препроцессинга конечно же).
#define MAKE_VAR(x) var_##x
int MAKE_VAR(test) = 42; // int var_test = 42;
Склеиваются именно токены. После препроцессинга должен получиться валидный токен:
#define BAD(a, b) a ## b
BAD(+, +) // ++ ✅
BAD(x, *) // x* ⛔️
Используется для генерации чего угодно. Часто думают только про имена функций/переменных/классов, но можно и для операторов, ключевых слов, литералы.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍14❤2