польза неопределенности (англ.)
(эта запись будет интересна только программистам и сочувствующим)
Интересная запись в блоге проекта LLVM о том, почему неопределенное поведение в стандарте C - полезная штука. Я знал эти аргументы теоретически (что неопределенное поведение позволяет компилятору более агрессивно оптимизировать код), но о подробных примерах никогда не задумывался:
Например:
Ну и еще в записи по ссылке есть несколько примеров такого рода.
Update: исходную запись почему-то удалили; я пока заменил своей копией.
Интересная запись в блоге проекта LLVM о том, почему неопределенное поведение в стандарте C - полезная штука. Я знал эти аргументы теоретически (что неопределенное поведение позволяет компилятору более агрессивно оптимизировать код), но о подробных примерах никогда не задумывался:
Например:
- если i - целая переменная с знаком, то компилятор может считать "i+1 > i" (или более сложное выражение, которое сводится к этому) автоматически истинным, несмотря на то, что для i==INT_MAX переполнение может сделать i+1 отрицательным. Если бы стандарт обязывал имплементацию C строго соблюдать "очевидную" логику переполнения, как это делает, например, Джава, то компилятор не смог бы почти никогда сделать эту оптимизацию.
Подчеркну: дело тут не только в том, что стандарты C не обязывают имплементацию использовать 'дополнительный код' (two's complement) для представления отрицательных целых чисел. Даже если все имплементации используют это представление - что де-факто верно в современном мире - и даже если бы по другим причинам это представление было бы обязательным согласно стандарту, все равно может быть полезным оставить результат INT_MAX+1 неопределенным, а не "очевидным" - в точности по причине, объясненной в предыдущем абзаце. Эту довольно тонкую идею я недостаточно хорошо понимал, кажется. - Последствия обращения к NULL-указателю не определены. В Джаве такое обращение гарантированно кидает исключение, и в этом несомненно есть много своих преимуществ; но как следствие этого, компилятор не может менять порядок вычисления других выражений относительно обращения к указателю. Например, если на Джаве написано что-то вроде: "c = a.b; c+= 5;", то компилятор не может сгенерировать код, который сначала поместит в c 5, а потом добавит содержимое a.b. Потому что если a==NULL, то исключение должно произойти до того, как в c что-то помещено. А C/C++ таких гарантий не дает, поведение неопределенное, поэтому компилятор может изменить порядок вычисления. В данном дурацком примере это ничему не поможет, но бывают случаи, когда это может сильно ускорить вычисление.
Ну и еще в записи по ссылке есть несколько примеров такого рода.
Update: исходную запись почему-то удалили; я пока заменил своей копией.
no subject
Поиск бага почти всегда стоит дороже, чем использование капельку более быстрого процессора.
(но я джаваист :) )
no subject
no subject
no subject
(Anonymous) 2011-05-12 08:26 pm (UTC)(link)Library design is language design. — Andrew Koenig
no subject
no subject
no subject
no subject
no subject
A ? B : C ? D : 0 = A ? B : CD = AB|(~A)CD, а (X = don't care)
A ? B : C ? D : X = A ? B : D = AB|(~A)D
no subject
если c - локальная переменная с областью действия меньше ближайшего try/catch - то видимо можно
а вообще больше всего мне конечно понравилось у Регера про баскетбол
no subject
no subject
интересно
Re: интересно
Re: интересно
Edited by Federico Biancuzzi and Shane Warden -- слово фортран не встречается ни разу...
Re: интересно
Re: интересно
no subject
В общем, необходимость объявленной неопределённости поведения - всё ещё сомнительная вещь для меня.
no subject
(Anonymous) 2011-05-13 07:18 am (UTC)(link)no subject
no subject
no subject
p.s. А пост уже удалили
no subject
(Anonymous) 2011-05-13 02:30 pm (UTC)(link)Ни одна из ссылок не работает
no subject
О каком 2's complement для unsigned может идти речь? Стандарт там очень аккуратно всё проговаривает. Более того, в нескольких местах явно говориться, что с unsigned по определению не бывает overflow.
Что такое "wild" pointer?
Тут автор даже не пытается явно упомянуть про другое распространенное заблуждение, что битовое представление null pointer это 0.
Нет такого правила; стандарт-то как раз и говорит, что if an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Т.е. замысел статьи очень правильный, но исполнение подкачало. Толковать стандарт надо очень аккуратно, внимательно следя за словоупотреблением, а то весь педагогический эффект пропадет.
no subject
Там же пояснено: random pointers (like NULL, pointers to free'd memory, etc).
> О каком 2's complement для unsigned может идти речь?
Имеется в виду, что поведение при переполнении аналогично. INT_MAX + 1 == INT_MIN. UINT_MAX + 1 == 0.
no subject
Зачем для красного словца изобретать "wild" и "объяснять" его через "random", когда стандарт написан в терминах valid/invalid?
Про доступ за границы массива - вообще какая-то каша ни о чем. Стандарт, кстати, вполне определяет осмысленные случаи доступа, которые будут "за границы" массива (см. напр. 6.5.9/6 про равенство указателя "за" последний элемент и указателя на первый элемент массива, который в памяти лежит непосредственно за первым массивом). Массивы и арифметика указателей в C и так одно из неочевидных мест, зачем еще больше путать людей?
Говорить о двоичном дополнительном представлении (отрицательных чисел!) в применении к беззнаковым(!) типам - это не просто неаккуратно, а очень неаккуратно. А уж фраза про то, что такое поведение беззнаковых определено "at least by Clang and other commonly available C compilers" - это уже просто за гранью добра из зла.
Впрочем, ну, "кто-то в интернете неправ", да и ладно. Разговоры про стандарт (на сколь-нибудь приемлемом уровне обсуждения) требуют слишком много сил и времени, а ни того, ни другого у меня просто нет.
Еще раз повторюсь, дело - благое, задумка - хорошая, а вот исполнение подвело.
no subject
Кстати, спасибо за подробные и информативные комментарии о языковых стандартах, выдержанные в корректном тоне; часто приходится видеть другое :-)
no subject
Мой скромный опыт толкования стандарта подсказывает, что если с терминологией быть поаккуратней, то обсуждение многих вопросов достигает каких-то положительных результатов гораздо быстрее. На самом деле можно (и было бы очень поучительно) много написать о том, как устроен язык стандарта, и как они там ловко выворачиваются, чтобы с одной стороны продолжать поддерживать (почти) все эти нижнеуровневые хаки а-ля ассемблер PDP-11, а с другой стороны поддерживать и совсем уж странные архитектуры.
Сравнивать с литералом 0 можно, но создает плохую привычку. В контексте varargs (например execl) приведение типов уже не спасет. Кажется именно с этим я в свое время сталкивался, собирая разный софт под Xenix/286 :)
Ну и раз уж зашла речь про unsigned - вот довольно милый, по-моему, пример на понимание этого места стандарта:
http://nxr.netbsd.org/xref/src/usr.bin/make/cond.c#487
Что делает
-(double)-l_valи почему это не хак, а вполне defined поведение.no subject
no subject
К примеру, sqrt сигнализирует об отрицательном аргументе в errno. В результате компилятор не может просто заменить функцию sqrt соответствующей инструкцией, кроме тех случаев когда он может доказать что аргумент не может быть отрицательным.