1.83K subscribers
3.23K photos
127 videos
15 files
3.52K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
#prog #rust #c

В C принято для функций-компараторов в сортировке возвращать целое число, где отрицательное значение означает, что первый элемент меньше второго, положительное — что первый элемент больше второго, а ноль — что элементы равны. В Rust же для этих целей используют отдельный тип Ordering. Между ними очень просто конвертироваться.

Из C в Rust:

fn c_order_to_rust_order(o: c_int) -> Ordering {
o.cmp(&0)
}

Из Rust в C:

fn rust_order_to_c_order(o: Ordering) -> c_int {
o as c_int
}

Второе работает за счёт дискриминантов на вариантах Ordering, расставленных ещё до релиза Rust 1.0. Определение Ordering, если опустить аннотации, выглядит так:

#[repr(i8)]
pub enum Ordering {
Less = -1,
Equal = 0,
Greater = 1,
}

Неудивительно, что rust_order_to_c_order компилируется в единственный mov (возможно, с sign extension, в зависимости от того, в какой конкретно тип кастовать).
👍112🤨1
1👎1
#prog #c #cpp #article

C Compilers Disprove Fermat’s Last Theorem

И продолжение: Compilers and Termination Revisited

TL;DR: Компилятор C++ может удалить цикл без побочных эффектов, не доказывая, что он завершается, ввиду forward progress guarantee, компилятор C11 может сделать то же самое для циклов, у которых условие не является константным выражением, ввиду §6.8.5.6, для более старых версий стандарта C без этой оговорки непонятно.

А, и это из-за бага в LLVM в своё время затронуло Rust (issue).
😁5
#prog #c #cpp #моё

Если вам вдруг понадобилось в рантайме выяснить, была ли ваша программа скомпилирована в режиме 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++ соответственно. Как видите, всё очень просто.
👍16🤯11🔥1
#prog #c #meme

Не вполне согласен с посылом растосучки — кто там sh написал?..
😁2💩1🖕1
#prog #c #cpp #article

How to check if a pointer is in a range of memory

Нет, просто сравнение указателей не работает. И, кстати, из соответствующего параграфа стандарта становится понятно, почему в C нельзя иметь типы нулевого размера.
🤔6
#prog #python #c #abnormalprogramming #article

Writing a C compiler in 500 lines of Python

С небольшим нюансом: компиляция в WASM и, понятное дело, только весьма небольшого подмножества C. Ну и для достижения ограничения на количество строк компилятор однопроходной.
👍3💩1