#prog #c #cpp #моё
Если вам вдруг понадобилось в рантайме выяснить, была ли ваша программа скомпилирована в режиме C или же C++, то вот непотокобезопасная функция, которая вернёт ответ в виде ноль-терминированной строки напрямую на большинстве систем:
...
Нет, всё-таки, как это действительно работает?
Первая строка объявляет переменную
Строковые литералы в C и C++ являются массивами
Что же касается второй строки... Что ж, тут надо разбираться.
Во-первых,
Во-вторых, в этой строчке
литерал символа имеет тип
Тут возникает вопрос, какой же размер у
Итак,
В-третьих, малоизвестный факт заключается в том, что в C и C++ в литерал символа можно записать больше одного символа, и называется это multi-character character literal. То, как именно эти литералы отображаются на численные значения, зависит от реализации — но нам это и не важно, потому что эти значения мы всё равно не используем. А вот что важно — так это то, что и в C, и в C++ такие литералы имеют тип
С учётом изложенного выше, а также того, что оператор деления и в C, и в C++ является левоассоциативным, можно подсчитать, какие же получаются индексы в функции. Для C это
5/4 - 4/2/4 = 1 - 2/4 = 1
, поэтому присваивание записывает конец строки аккурат после первого символа
5/1 - 4/2/1 = 5 - 2/1 = 3
, потому присваивание записывает ноль после второго
В третьей строке строка возвращается, и из-за объявленного типа массив деградирует до указателя на его первый элемент. Признаком конца строки в C является ноль-символ, поэтому все функции стандартной библиотеки считают возвращаемое значение строкой
Если вам вдруг понадобилось в рантайме выяснить, была ли ваша программа скомпилирована в режиме C или же C++, то вот непотокобезопасная функция, которая вернёт ответ в виде ноль-терминированной строки напрямую на большинстве систем:
Как же это работает? В отдельной переменной записывается строка, в нужную позицию записывается признак конца строки, а затем строка возвращается. Всем пока.
char const* get_language() {
static char s[] = "C++\?";
s[sizeof s/sizeof'C'-sizeof'++'/2/sizeof'\?']=0;
return s;
}
...
Нет, всё-таки, как это действительно работает?
Первая строка объявляет переменную
s и присваивает ей значение. Переменная s статическая, чтобы возвращаемый указатель не становился висячим сразу после возврата из функции.Строковые литералы в C и C++ являются массивами
char-ов, включающими в себя неявно добавляемый на фазе трансляции терминирующий нуль-символ. s объявлена, как переменная типа char[]. Обычно тип в C(++) нужно выписывать целиком, но длину массива в объявлении переменной можно опустить, если её можно вывести из типа инициализирующего выражения — как в этом случае. Строка "C++\?" имеет четыре символа (четыре, потому что \? является escape-ом для ? (потому что триграфы)), поэтому с учётом конечного нуля получаем, что s имеет тип char[5].Что же касается второй строки... Что ж, тут надо разбираться.
Во-первых,
sizeof является унарным оператором и, вообще говоря, не требует скобок. При этом у него приоритет выше, чем у арифметических выражений, поэтому в выражении ниже они и не требуются. Не то чтобы это было сильно важно для понимания, но не все об этом знают.Во-вторых, в этой строчке
sizeof применяется к, в частности, литералу символа. Чему равно значение этого выражения? Казалось, это должно быть 1, поскольку стандарт C прямо диктует (а стандарт C++ вторит), что sizeof(char) равен 1. Но! Тут мы применяем sizeof к литералу символа, и тут кроется одно из отличий между C и C++, делающее эту функцию возможной:литерал символа имеет тип
int в C и тип char в C++.Тут возникает вопрос, какой же размер у
int. Если вы программируете не под микроконтроллеры, то на вашей целевой системе тип int наверняка имеет размер 4 байта. Строго говоря, это не всегда верно, поскольку размер int является implementation defined, но это настолько распространённое и работающее на практике заблуждение, что после появления 64-битных систем размер int остался на них 4 байта. Не смотря на то, что int по замыслу является целым числом нативного для машины размера, смена размера int на 64-битных платформах до 8 байт сломала бы слишком много программ.Итак,
sizeof'C' и sizeof'\?' возвращает 4 для C и 1 для C++. sizeof s возвращают размер типа s. Для массива это размер в байтах. Так как s имеет тип char[5], sizeof s возвращает 5. Но вот что такое sizeof'++'? Нет, это не опечатка.В-третьих, малоизвестный факт заключается в том, что в C и C++ в литерал символа можно записать больше одного символа, и называется это multi-character character literal. То, как именно эти литералы отображаются на численные значения, зависит от реализации — но нам это и не важно, потому что эти значения мы всё равно не используем. А вот что важно — так это то, что и в C, и в C++ такие литералы имеют тип
int. Так что sizeof'++' возвращает таки 4.С учётом изложенного выше, а также того, что оператор деления и в C, и в C++ является левоассоциативным, можно подсчитать, какие же получаются индексы в функции. Для C это
5/4 - 4/2/4 = 1 - 2/4 = 1
, поэтому присваивание записывает конец строки аккурат после первого символа
C. Для C++ же5/1 - 4/2/1 = 5 - 2/1 = 3
, потому присваивание записывает ноль после второго
+.В третьей строке строка возвращается, и из-за объявленного типа массив деградирует до указателя на его первый элемент. Признаком конца строки в C является ноль-символ, поэтому все функции стандартной библиотеки считают возвращаемое значение строкой
"C" в C и "C++" в C++ соответственно. Как видите, всё очень просто.godbolt.org
Compiler Explorer
Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code.
👍16🤯11🔥1
Ну и напоследок о том, как можно эту функцию улучшить. В C++, в отличие от C, поддержка multi-character character literal является необязательной, поэтому конформная реализация C++ может попросту не скомпилировать эту функцию. Для того, чтобы улучшить переносимость между языками, можно убрать этот литерал и заменить
sizeof'++'/2 на (sizeof'+'+sizeof'+').👍3
То есть не только пошёл спать под утро, так ещё и вместо того, чтобы спать, дочитывал ЛВПГ.
Нет, не жалею об этом.
Нет, не жалею об этом.
💩4👍2🤔2
#video
Или немного о том, что из себя представляет это ваше программирование (метафорически).
youtube.com/watch?v=cDA3_5982h8
Или немного о том, что из себя представляет это ваше программирование (метафорически).
youtube.com/watch?v=cDA3_5982h8
YouTube
Exact Instructions Challenge - THIS is why my kids hate me. | Josh Darnit
Exact Instructions Challenge PB&J edition
Another Challenge with Johnna and Evan: https://www.youtube.com/watch?v=sLaVM6af-RE&t=121s
We asked the kids to write instructions for a simple task but left out that we were going to be following their instructions…
Another Challenge with Johnna and Evan: https://www.youtube.com/watch?v=sLaVM6af-RE&t=121s
We asked the kids to write instructions for a simple task but left out that we were going to be following their instructions…
👍4
Forwarded from /17 --verbose --public --35
Рисунок моего старшего брата. Акварелью (!)
Иногда я в шоке с этого мужика. К слову, картина продаётся.
https://www.reddit.com/r/Watercolor/comments/10fmd3q/i_found_1mm_brush_on_the_street_literally_thanks/
Иногда я в шоке с этого мужика. К слову, картина продаётся.
https://www.reddit.com/r/Watercolor/comments/10fmd3q/i_found_1mm_brush_on_the_street_literally_thanks/
🤯24🔥3😍3
В общем, у меня нету доступа к двум аккаунтам Microsoft.
Один из них я завёл в ходе миграции аккаунта Mojang, и я бы этого не делал, не будь это обязательным. Я не помню email и пароль от этого нового аккаунта, но оно мне и не было нужно, потому что вход в аккаунт сохранялся и мне не нужно было вводить его каждый раз. Однако вот сейчас при запуске лаунчера Minecraft он обновился и эта инфа слетела, и я теперь не могу войти, потому что ничего не помню, а по gamertag Microsoft ничего восстановить не может. Жутко неприятно, но жить можно.
А вот со вторым аккаунтом — точнее, адресом электронной почты на Outlook — всё куда хуже. Он использовался у меня как минимум для Discord (и ещё для каких-то ). Поменять email, используемый для аккаунта Discord, сами разрабы не могут. И вот с этим вторым аккаунтом я фактически сам загнал себя в ловушку: предоставил выдуманное имя (что-то в духе Anyone Idontcare), дал минимум персональных данных, в качестве адреса для верификации (без которого мне просто не давали завести аккаунт) дал адрес из сервиса для пятиминутных email. Как оказалось, я забыл пароль оттуда. Судя по всему, я его поменял и при этом запомнил старый пароль, а не новый. В итоге я теперь из Discord выйти могу, а вот войти обратно — уже нет. И восстановлением доступа к аккаунту я воспользоваться не могу: я не могу предоставить достаточно деталей, чтобы "автоматизированная система" разрешила рассматривать этот случай. В частности, я не могу предоставить темы последних моих писем, поскольку с этого аккаунта я письма только получал, но не отправлял.
Такие дела.
Не знаю, что делать. Разве что надеяться на то, что среди моих подписчиков есть кто-то со связями в Microsoft.
Один из них я завёл в ходе миграции аккаунта Mojang, и я бы этого не делал, не будь это обязательным. Я не помню email и пароль от этого нового аккаунта, но оно мне и не было нужно, потому что вход в аккаунт сохранялся и мне не нужно было вводить его каждый раз. Однако вот сейчас при запуске лаунчера Minecraft он обновился и эта инфа слетела, и я теперь не могу войти, потому что ничего не помню, а по gamertag Microsoft ничего восстановить не может. Жутко неприятно, но жить можно.
А вот со вторым аккаунтом — точнее, адресом электронной почты на Outlook — всё куда хуже. Он использовался у меня как минимум для Discord (и ещё для каких-то ). Поменять email, используемый для аккаунта Discord, сами разрабы не могут. И вот с этим вторым аккаунтом я фактически сам загнал себя в ловушку: предоставил выдуманное имя (что-то в духе Anyone Idontcare), дал минимум персональных данных, в качестве адреса для верификации (без которого мне просто не давали завести аккаунт) дал адрес из сервиса для пятиминутных email. Как оказалось, я забыл пароль оттуда. Судя по всему, я его поменял и при этом запомнил старый пароль, а не новый. В итоге я теперь из Discord выйти могу, а вот войти обратно — уже нет. И восстановлением доступа к аккаунту я воспользоваться не могу: я не могу предоставить достаточно деталей, чтобы "автоматизированная система" разрешила рассматривать этот случай. В частности, я не могу предоставить темы последних моих писем, поскольку с этого аккаунта я письма только получал, но не отправлял.
Такие дела.
Не знаю, что делать. Разве что надеяться на то, что среди моих подписчиков есть кто-то со связями в Microsoft.
😢10💩5👍3🤡3