Про целочисленные типы
Apr. 5th, 2016 10:38 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Интересно, что количество бит в самом большом целочисленном типе, поддерживаемом современными компиляторами (int128_t), уже сравнялось с максимальным значением самого маленького (signed char).
Это к вопросу о том, как интерпретировать x << -1.
Мне пришли в голову две «естественные» интерпретации:
1. x << -1 = x >> 1.
2. x << -1 = x<< ((usigned что-то)-1) = x << 255 или x << 65535 и так далее.
В обоих случаях 1 << -1 = 0.
Но не все компиляторы с этим согласны. (понятно что по стандарту это undefined behavoir).
Это к вопросу о том, как интерпретировать x << -1.
Мне пришли в голову две «естественные» интерпретации:
1. x << -1 = x >> 1.
2. x << -1 = x<< ((usigned что-то)-1) = x << 255 или x << 65535 и так далее.
В обоих случаях 1 << -1 = 0.
Но не все компиляторы с этим согласны. (понятно что по стандарту это undefined behavoir).
no subject
Date: 2016-04-05 08:33 am (UTC)no subject
Date: 2016-04-05 08:37 am (UTC)Google: Obfuscated C contest
no subject
Date: 2016-04-05 08:37 am (UTC)no subject
Date: 2016-04-05 09:30 am (UTC)no subject
Date: 2016-04-05 09:31 am (UTC)no subject
Date: 2016-04-05 09:40 am (UTC)no subject
Date: 2016-04-05 04:20 pm (UTC)А новым Паскалем окажется, я надеюсь, какой-нибудь из языков "новой волны". Более-менее неважно какой, любой из них лучше, чем сложившаяся сейчас ситуация. Да хоть бы та же няшная Гошечка. :-) (хотя у него, разумеется, свои недостатки, но у кого их нет? И, кстати, "язык слишком бедный, в нём нет того, того и вон того" к недостаткам не относится).
... Ледяные ласки огненных лисиц ...
no subject
Date: 2016-04-05 09:07 am (UTC)- ошибок обновления компилятора. Так как сегодняшняя версия компилирует один код, а завтрашняя - другой. Просто из-за того, что поведение undefined - никто не тестировал.
- ошибок обновления кода. Опять же - при редактировании собственной программы автор не задумывается о данном кусочке, ичто он изменит работу.
- ошибок несовместимости архитектур ПРОЦЕССОРА - "на x86 работаем, на x64 нет" хотя бы
- ошибок различия сред исполнения. Пример из реальной жизни - одна и та же ДОС/Win95 программа, запущенная в досбокс в современной Windows. Ещё смешнее - одна и та же программа, запущенная в английской и русской версиях операционки. Достаточно ОДНОГО национального символа в одном пути к файлу чтобы получить потрясающие спецэффекты.
no subject
Date: 2016-04-05 09:26 am (UTC)А через двадцать лет появляется новый компилятор который на это говорит "фу". Я тут было дело недавно правил подобного рода конструкцию в catdoc. Не помню зачем я ее написал во времена turbo C 2.0, но вот CLang на 64-битной архитектуре жрать отказался.
Но вообще когда у тебя "на x86 работаем, а на x64 нет", это полбеды. Вот когда "на x86 работаем, на x64 работаем, на ARMv5 работаем, а на ARMv7 внезапно нет"...
no subject
Date: 2016-04-05 09:40 am (UTC)no subject
Date: 2016-04-05 12:58 pm (UTC)no subject
Date: 2016-04-05 01:09 pm (UTC)От разных endianness тоже, кстати.
И вот такой код
struct A {
whatever1 x;
whatever2 y;
whatever3 z;
} a[2];
write(fd, a, sizeof(a));
может нанести немало неожиданностей даже для типов whatever... из этой библиотеки.
no subject
Date: 2016-04-05 03:14 pm (UTC)no subject
Date: 2016-04-05 03:27 pm (UTC)no subject
Date: 2016-04-05 09:43 am (UTC)no subject
Date: 2016-04-05 09:57 am (UTC)хождения строемпростого и читаемого кода. Собственно, нет причин для спора.Однако, мне действительно интересно, где в современном мире могут быть всерьез нужны фокусы с булевой арифметикой ? Навскидку приходят в голову только IP адреса и маски, потому что, на сколько я понимаю, сейчас даже контроллер осещения в "умном доме" тупо дешевле сделать на x64, под линуксом и, соответственно, с полным набором языков высокого уровня.
BTW, мб вспомним фидошные времена и перейдем на ты ?
no subject
Date: 2016-04-05 11:13 am (UTC)Даже самый простой и читаемый код может оказаться неработоспособным просто из-за того, что входящие данные незаметно сменили кодировку "на низком уровне".
фокусы с булевой арифметикой
...
тупо дешевле сделать на x64, под линуксом и, соответственно, с полным набором языков высокого уровня.
То есть НЕ СЛЕДУЕТ ВООБЩЕ употреблять "данных низкого уровня" и обрабтку "низкого уровня" при написании программ (на любом языке, высокого ли уровня или нет - не важно)?
И, конечно же, написанный и откомпилированный сейчас код "на языке высокого уровня" никогда не нарвётся на то, что обрабатываемые им данные существенно изменились?
Умный дом? С автоапдейтящимися прошивками в железках, ога. Спасибо.
Через 5 лет, после смены таймзоны и апдейта прошивки под оную смену (например) - что будете делать (реальный случай - размер буфера под выдаваемой некоторой прошивкой текстовое представление времени оказался недостаточен при изменении наименования таймзоны, в результате - атака по переполнению стека и креш системы)? А что будет делать клиент, если автор программы "высокого уровня" в одном из контроллеров успел помереть?
Ах, ФИДО? См. bink plus и необходимость добавить 42 в одном месте в календарном расчёте в СТАНДАРТНОЙ библиотеке в 2000 году. Раскопано Киром Злобиным.
Runtime Error в паскалевских (дада, язык высокого уровня!) программах ДОС эпохе при запуске на достаточно быстрых процессорах.
Правда, зачем думать о низком уровне? Давайте писать на высоком и не думать вообще. :)
no subject
Date: 2016-04-05 11:34 am (UTC)Что касается Runtime Error 200 то это как раз проблема низкого уровня. Попала в комплект распространенного компилятора кривая ассемблерная библиотека с неудачно написанным кодом инициализации. Причем попала фактически в качестве учебного примера. Уровня совместимости с GW-Basic, которым при написании приличных программ пользоваться не следует. Возможно, поэтому борландовцы и не исправили вовремя - у них уже в 93-м был Turbo Vision, которым и рекомендовалось пользоваться ВМЕСТО Crt.
Существуют альтернативные библиотеки tpcrt и opcrt (из комплекта Turbo Professional и Object Professional соответственно), где этой проблемы нет. Я еще году в 95-м, когда Турбо Паскаль был основным моим рабочим языком, писал в юзнете что модуль CRT вреден и использование его - признак чайника.
no subject
Date: 2016-04-05 12:34 pm (UTC)И потому выбирает "сердцем". :)
А клиент потом вынужден отказываться от применения откомпилированной таким образом программы. Или искать к ней патч ещё более низкого уровня (hiew/...), чем ассемблер.
Собственно - так и пришлось в 2000 году патчить кусочек сишной библиотеки в bink+.
no subject
Date: 2016-04-05 12:18 pm (UTC)>То есть НЕ СЛЕДУЕТ ВООБЩЕ употреблять "данных низкого уровня" и обрабтку "низкого уровня" при написании программ (на любом языке, высокого ли уровня или нет - не важно)?
Где я это сказал ?
Я просил привести пример оправданного прменения булевой арифметики в современной программе.
> Умный дом? С автоапдейтящимися прошивками в железках, ога. Спасибо. Через 5 лет, после смены таймзоны и апдейта прошивки под оную смену (например) - что будете делать (реальный случай - размер буфера под выдаваемой некоторой прошивкой текстовое представление времени оказался недостаточен при изменении наименования таймзоны, в результате - атака по переполнению стека и креш системы)? А что будет делать клиент, если автор программы "высокого уровня" в одном из контроллеров успел помереть?
В моем случае, клиент будет лежать в гробу, глубоко безразличный к проблеме, тк умный дом он строит для себя сам. :-)
В стандартном - свяжется с саппортом, или (если это будет очень умный клиент :-) соберет нужную прошивку сам из открытых исходников.
Вообще, мне кажется, термин прошивка не совсем применим к современным устройствам. Правильнее говорить про ОС и прикладной софт. Соответственно, нормальный процесс исправления ошибок в прикладном софте. Как вариант - зайти на контроллер ssh-м и обновить соответствующий пакет.
Но как это все связано с изначальным разговором про булеву арифметику, мне не очень понятно.
> Правда, зачем думать о низком уровне? Давайте писать на высоком и не думать вообще. :)
Ну, как бы, да. Мир к тому идет. В частности, Вашими усилиями. Нет ?
no subject
Date: 2016-04-05 12:38 pm (UTC)Почти любая реализация видеокодеков.
Содержательная обработка данных с конкретного железа.
При соответствующе документированном протоколе.
no subject
Date: 2016-04-05 12:41 pm (UTC)По дороге сам вспомнил про криптографию :-)
no subject
Date: 2016-04-05 03:10 pm (UTC)Компактные сетевые протоколы с быстрым парсингом, кстати. Типа CBOR. Она там примитивная, но есть, и обеспечивает компактность.
Когда данных надо передать МНОГО, компактность протокола ой, важна...
no subject
Date: 2016-04-05 03:33 pm (UTC)AreaLink[area_off] |= here_mask1;
AreaLink[area_off] &= here_mask0;
area_off - понятное дело, адрес байта. :)
no subject
Date: 2016-04-05 03:30 pm (UTC)И, кстати, конкретно эта засада единственно правильным способом не засажена в языке Ада (да-да, том самом): там есть ДВЕ операции `mod` и `rem`. Если их две, то ты невольно задумаешься, какая именно из них нужна. А если у тебя только `%`, который совпадает с одной из них, причём не с той -- вопрос имеет куда более высокие шансы быть проигнорированным.
... Маркс, Кейнс и кот Матроскин ...
no subject
Date: 2016-04-05 12:11 pm (UTC)Почему бы не требовать ручной конвертации типов? Чтобы такое нельзя было:
unsigned int x=foo();
...
signed int y = x/2;
и т.д. Т.е. строгая типизация с правом typecast'инга как душе взбредёт. Но явным.
no subject
Date: 2016-04-05 02:23 pm (UTC)Ну а на случай, если значение вписывается в unsigned, но не вписывается в signed или когда программист не подумал, что число помещенное в unsigned может быть отрицательным - тут уж он сам виноват. Хотя, конечно, незамеченное изменение спецификации API, которое будет замечено с меньшей вероятностью из-за отсутствия ворнингов при перекомпиляции - это неприятно.
no subject
Date: 2016-04-05 03:29 pm (UTC)Нормальный подход (задним числом, спустя несколько десятилетий после создания языка) - сделать типизацию строгой.
То есть никакой конверции unsigned/signed. Хочешь конверсию - делай либо typecasting, либо пиши явно что делать.
Сколько бы при этом граблей прошло - словами не описать. А написать чуть больше union'ов - ни у кого бы руки не отвалились.
Заодно, кстати, и на int (x64) перешли бы по-человечески, потому что к этому моменту все бы точно знали из чего во что конвертят.
Неявное приведение типов - как открытый люк на хайвее. Внимательный водитель заметит и объедет. Невнимательный может быть проскочит, а может быть и без оси останется.
no subject
Date: 2016-04-05 03:37 pm (UTC)>(задним числом, спустя несколько десятилетий после создания языка) - сделать типизацию строгой.
наверняка было бы дофига головной боли,
мне ничего не остается, как согласиться с Вашими аргументами.
no subject
Date: 2016-04-05 07:36 pm (UTC)no subject
Date: 2016-04-06 04:06 am (UTC)Самый эпичный баг нестрогости системы типов в плюсах, который я сажал, был, когда я поменял тип одной переменной с
int
наint8_t
.no subject
Date: 2016-04-06 08:38 am (UTC)Компилятор увидел, что оператора
>> (int8_t &)
не завезли, после чего сделал по сути вот такой код для вызова оператора>> (int &)
int8_t bar;
std::istringstream iss2("3");
int bar_replacement = (int)bar;
iss2 >> bar_replacement;
А в переменной bar осталось то, что осталось.
По-хорошему, за подмену ссылочного типа без явного каста компилятор должен бить по рукам гораздо сильнее, чем за подмену скалярного. А тут он сам занялся даже не просто подменой ссылочного типа, а подменой самой ссылки. Для оператора << это сошло бы с рук, а для >> вышло то, что вышло.
no subject
Date: 2016-04-06 09:09 am (UTC)no subject
Date: 2016-04-06 09:23 am (UTC)Тоже неплохо :)
no subject
Date: 2016-04-06 09:30 am (UTC)Ну то есть легенды о реализациях C, где char имеет размер 32 бита я слышал, но живьем никогда не видел.
no subject
Date: 2016-04-06 09:33 am (UTC)А вот какому-нибудь short short'у никто не запрещает тоже иметь размер 1 байт.
no subject
Date: 2016-04-06 09:41 am (UTC)Существовали архитектуры, в которых минимальным адресуемым фрагментом было машинное слово. Там как ни крути, всегда получалось, что размер любого типа кратен размеру слова.
no subject
Date: 2016-04-06 10:01 am (UTC)no subject
Date: 2016-04-06 10:21 am (UTC)no subject
Date: 2016-04-06 10:38 am (UTC)int8_t
был бы отдельным примитивным типом. Но в стандарте написано, что это typedef на какой-нибудь знаковый целочисленный тип на усмотрение реализации. В моей реализации —typedef signed char int8_t
.no subject
Date: 2016-04-05 02:39 pm (UTC)Если тип первого аргумента не помещается в регистр - сдвиг происходит в несколько шагов. Разумеется при этом компилятор полагает, что правый аргумент неотрицательный, в ином случае - возможны самые разные приколы, позволяющие UB отстрелить ногу неосторожного прогера.
Или Вы хотите, чтобы компилятор был умнее программиста и при каждом битовом сдвиге генерил инструкции проверки знака второго аргумента?
no subject
Date: 2016-04-06 04:14 am (UTC)Достаточно умный компилятор ещё замечает использование выражения в правом аргументе оператора сдвига и начинает использовать его для оптимизации всего вокруг.
Если известно, что
do_something()
не бросает исключений, не завершает программу и не зацикливается, то компилятор имеет право объявить весьif
мёртвым кодом и выоптимизировать.no subject
Date: 2016-04-06 12:47 pm (UTC)no subject
Date: 2016-04-06 01:55 pm (UTC)no subject
Date: 2016-04-06 01:26 pm (UTC)if (ptr == NULL) {
do_something();
}
*ptr = 0;
Всё же прежде чем сломаться в том, что после if'а, хорошо бы сначала выполнить имеющий побочные эффекты код внутри него.
no subject
Date: 2016-04-06 01:59 pm (UTC)Я пропустил условие, что foo не меняется между проверкой и использованием в правом аргументе сдвига.
Безопасностные дырки, основанные на том, что компилятор выоптимизировал что-нибудь, руководствуясь принципом «если бы это было нельзя выоптимизировать, тут в любом случае бы было UB», были.
no subject
Date: 2016-04-06 02:11 pm (UTC)Суть в том, что это неправильный компилятор, который заранее решает, что предусловия второй части кода выполнены, а посему закроем глаза и будем надеяться на лучшее, а значит, иф из первой части кода не нужен.
no subject
Date: 2016-04-06 03:35 pm (UTC)Факт тот, что стандарт разрешает делать такие оптимизации, и что реальные компиляторы их делают.
no subject
Date: 2016-04-06 08:58 pm (UTC)