jsn: (common)
[personal profile] jsn

[несколько слов пропущено, потому что они все нецензурные]

jason@jsn c $ cat r.c
#include <stdio.h>

#define B (sizeof(int) * 8)
int _ = B ;
int f(void) { return _ ; }

unsigned g(unsigned x) {
    printf("x == %d, ", x) ;
    return 1 << (B - x) ;
}

int main(int ac, const char *av[]) {
    printf("g(x) == %d\n", g(0)) ;
    printf("g(x) == %d\n", g(B - f())) ;
    return 0 ;
}
jason@jsn c $ gcc -o r r.c && ./r
x == 0, g(x) == 1
x == 0, g(x) == 1
jason@jsn c $ gcc -O2 -o r r.c && ./r
x == 0, g(x) == 0
x == 0, g(x) == 1
jason@jsn c $ clang -o r r.c && ./r
x == 0, g(x) == 1
x == 0, g(x) == 1
jason@jsn c $ clang -O2 -o r r.c && ./r
x == 0, g(x) == 0
x == 0, g(x) == 1
jason@jsn c $ 

Это, что, считается нормально теперь? Там, что, в стандарте действительно сказано, что overflowing left shift result is undefined? И "undefined" следует интерпретировать как "ведёт себя по-разному в соседних строчках кода?"

Date: 2013-02-14 02:36 pm (UTC)
From: [identity profile] dmarck.livejournal.com
"undefined" != "implementation-defined", ain't it?

Но, да, некрасиво, хоть и неудивительно. а на -Wall что компиляторы говорят?

Date: 2013-02-14 02:41 pm (UTC)
From: [identity profile] jsn.livejournal.com
Ничего не говорят, конечно. (1 << 32) == 1, причём только при -O2 и выше и только иногда даже при этом -- это не implementation defined как-то :)

Date: 2013-02-14 02:43 pm (UTC)
From: [identity profile] ilya-dogolazky.livejournal.com
Ответ на все три вопроса "ну типа да". Ответ "ноль" получен, видимо, прямо во время компиляции, и является "верным" (ну то есть не по правилам языка, а по нашему преставлению о том, сколько будет 1<<32). Ответ "1" честно вычислен микропроцессорной командой сдвига во время исполнения, на i386 процессорах (по крайней мере на некоторых, за все не скажу) длина сдвига берётся только из младших пяти битиков.

Date: 2013-02-14 02:49 pm (UTC)
From: [identity profile] jsn.livejournal.com
Мощно, спасибо. [livejournal.com profile] sgt, впрочем, сообщает, что у него на clang-е:
x == 0, g(x) == 4195907
x == 0, g(x) == 1

... но да, если уж undefined и всё так ужасно, то чего мелочиться-то. Что ж, придётся усыпать код омерзительными if-ами.

Date: 2013-02-14 03:51 pm (UTC)
From: [identity profile] alexott.livejournal.com
у меня на 64-bit линуксе и clang (с -O2, clang 3.0):
x == 0, g(x) == 4195973
x == 0, g(x) == 1

Date: 2013-02-14 03:52 pm (UTC)
From: [identity profile] jsn.livejournal.com
У меня clang 3.2; 4195973 всё ж похоже на баг в clang-е.

Гы. промежуточное

Date: 2013-02-14 04:19 pm (UTC)
From: [identity profile] dmarck.livejournal.com
marck@castor:~/tmp/jsn-shift> clang -O2 -o r r.c && ./r
x == 0, g(x) == 4196043
x == 0, g(x) == 1
marck@castor:~/tmp/jsn-shift> clang --version
FreeBSD clang version 3.1 (branches/release_31 156863) 20120523
Target: x86_64-unknown-freebsd9.0
Thread model: posix
marck@castor:~/tmp/jsn-shift> uname -a
FreeBSD castor.rinet.ru 9.1-STABLE FreeBSD 9.1-STABLE #0 r245742: Mon Jan 21 21:29:07 MSK 2013
     marck@castor.rinet.ru:/usr/obj/usr/src/sys/CASTOR  amd64
Edited Date: 2013-02-14 04:27 pm (UTC)

Date: 2013-02-14 03:03 pm (UTC)
From: [identity profile] trurle.livejournal.com
Это, что, считается нормально теперь?

Не только теперь, но с 1973 года. C language: enabling shooting yourself in the foot for 40 bloody years!

Date: 2013-02-14 03:07 pm (UTC)
From: [identity profile] alexott.livejournal.com
"1972 - Dennis Ritchie invents a powerful gun that shoots both forward and backward simultaneously. Not satisfied with the number of deaths and permanent maimings from that invention he invents C and Unix."

Date: 2013-02-14 03:24 pm (UTC)
From: [identity profile] ilya-dogolazky.livejournal.com
Я вот не понимаю этих шуточек, пример со сдвигом как раз показывает очень большое достоинство языка Си --- он выполняет сдвиг одной единственной инструкцией (где может). Сделать это (на i386 к примеру) с различением сдвига на 0 и сдвига на 32 разряда невозможно, вот он и не делает, причём честно об этом говорит в стандарте.

Date: 2013-02-14 03:36 pm (UTC)
From: [identity profile] jsn.livejournal.com
Беспокоит собственно не это, а неконсистентность. g() [вполне себе const unsigned g(x)], которая не зависит ни от чего, кроме x, тем не менее возвращает разные значения при одном и том же x. Нехорошо это.

Date: 2013-02-14 03:52 pm (UTC)
From: [identity profile] alexott.livejournal.com
а потом ты проводишь часы медитируя над кодом, поскольку не всегда можешь понять откуда ты получил такое число, и почему оно работает на соседней машине...

Date: 2013-02-14 04:02 pm (UTC)
From: [identity profile] ilya-dogolazky.livejournal.com
Есть альтернатива: (а) медитировать часами (б) компилировать КАЖДЫЙ сдвиг в два сравнения с ветвлением плюс одну инструкцию собственно сдвига. Вам какой вариант кажется подходящим?

Date: 2013-02-14 04:54 pm (UTC)
From: [identity profile] juan-gandhi.livejournal.com
Какое ж это достоинство, это дефект.

Date: 2013-02-14 08:48 pm (UTC)
From: [identity profile] jsn.livejournal.com
Для ассемблера, например, это очевидное достоинство.

Date: 2013-02-14 10:53 pm (UTC)
From: [identity profile] kika.livejournal.com
это дефект для тех, кому язык С не нужен. педальный привод велосипеда тоже дефект для автомобиля.

Date: 2013-02-14 09:28 pm (UTC)
From: [identity profile] cherry-merry.livejournal.com
о боже, о чем вы? :-)
с праздничком тебя! Любви!

Date: 2013-02-14 09:53 pm (UTC)
From: [identity profile] jsn.livejournal.com
спасибо; и тебя :)

Date: 2013-02-14 10:41 pm (UTC)
From: [identity profile] ifp5.livejournal.com
И "undefined" следует интерпретировать как "ведёт себя по-разному в соседних строчках кода?"


Ну скорее как "может вести себя по разному в ...". Может стереть данные на диске, сжечь материнскую плату, устроить ядерную войну... А какие еще варианты то?

Date: 2013-02-14 10:47 pm (UTC)
From: [identity profile] ifp5.livejournal.com
Очень, кстати, хочу компилятор и пр. чтобы в случае UB программа сразу же валилась.

Date: 2013-03-29 07:49 pm (UTC)
From: [identity profile] helvegr.livejournal.com
В clang есть -fsanitize=undefined.
http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
Вот отчёт о его применении к libc++:
http://cplusplusmusings.wordpress.com/2013/03/26/testing-libc-with-fsanitizeundefined/

Date: 2013-02-14 10:52 pm (UTC)
From: [identity profile] kika.livejournal.com
undefined на то и undefined, что его можно как угодно интерпретировать. представь себе что популярная реализация в месте undefined оставляет верхушку стека? вот и будет что попало

Date: 2013-02-14 11:02 pm (UTC)
From: [identity profile] jsn.livejournal.com
право же, помандейтить, чтобы const funcs по крайней мере вели себя как const func (== результат не зависит ни от чего, кроме аргументов) -- это меньшее, что разумно было бы сделать.

Date: 2013-02-15 12:47 am (UTC)
From: [identity profile] kika.livejournal.com
не. она ведет себя одинаково же. undefined == undefined, whatever value of undefined is. а ты выходишь за рамки этого понимания и требуешь чтобы у тебя было undefined0 и undefined1, а этого тебе никто не обещал.

Date: 2013-02-14 11:07 pm (UTC)
From: [identity profile] jsn.livejournal.com
...впрочем, да, в Си const func-и -- одна вывеска, и это оверкилл. но помандейтить, чтобы left shift хотя бы вёл себя консистентно-то можно было б.

Date: 2013-02-15 12:49 am (UTC)
From: [identity profile] kika.livejournal.com
только ценой дополнительных проверок и инструкций. С - это работа на открытом сердце, дополнительные проверки не входят.

ты, кстати, http://www.amazon.com/gp/product/B009RAOZ8M/ref=docs-os-doi_0 читал?

Date: 2013-02-15 12:55 am (UTC)
From: [identity profile] jsn.livejournal.com
да не, каких проверок-инструкций-то, в данном случае? всего лишь достаточно, чтобы compiler precomputed lshift был реализован той же инструкцией, что и compiled lshift.

читал, кажется; не особо впечатлило, по-моему.

edit: ну то есть понятно, что это требует довольно продвинутой модели target-а при кросс-компиляции; но в собственно порождаемом коде это никакого оверхеда не приносит.
Edited Date: 2013-02-15 01:02 am (UTC)

Date: 2013-02-15 01:04 am (UTC)
From: [identity profile] kika.livejournal.com
ну то есть тебя устроит если константный шифт будет вести себя адекватно, а не константный - хер знает как?

Date: 2013-02-15 01:09 am (UTC)
From: [identity profile] jsn.livejournal.com
наоборот, как раз сейчас оно так и делает, и меня это сбивает с ритма. меня устроит, чтобы константный шифт вёл себя так, как если бы его скомпилили и запустили.

Date: 2013-02-17 03:53 am (UTC)
From: [identity profile] evolver.livejournal.com
У меня есть несколько иная точка зрения на происходящее. Она основана на чтении результата трансляции с флажком "-S". Очень вероятно, что никакого константного шифта при опции "-O2" не cлучается. Компилятор инлайнит функцию g() в тело main(), причем делает это двумя разными способами. Для случая вызова g(0) он оптимизирует все до состояния, где в printf для g(0) попадает мусор после printf для x. Забавно наблюдать результат двух или более последовательных вызовов бинарника, скомпилированного с -O2. Кажый раз мы видим новый результат.

Фактическая инструкция "shll" выполняется только для второго инлайна функции g() в теле main(). Смотри строку 30 в этом фрагменте:
http://codepad.org/XBCaHfIo

Она как раз возвращает стабильный результат.

Вариант без "-O2" честно геренрирует и дважды вызывает функцию g(), которая честно содержит "shll". Наверно это объясняет наблюдаемое поведение.

Для меня загадкой остается то, зачем компилятор сохраняет в коде отдельную реализацию g(), которая никогда не вызывается, но это уже другая тема.

Date: 2013-02-18 09:13 am (UTC)
From: [identity profile] jsn.livejournal.com
никакого константного шифта при опции "-O2" не cлучается ... Для случая вызова g(0) он оптимизирует все до состояния, где в printf для g(0) попадает мусор после printf для x

Это не называется "оптимизирует" -- это баг. Константный шифт на 32, будучи undefined, сочтён nop-ом и несэмичен.

Фактическая инструкция "shll" выполняется только для второго инлайна функции g() в теле main().

Конечно; так и должно быть в случае precomputed vs emitted.

Date: 2013-02-18 09:51 am (UTC)
From: [identity profile] jsn.livejournal.com
Для меня загадкой остается то, зачем компилятор сохраняет в коде отдельную реализацию g()

Очевидно, потому что она не static, и поэтому может вызываться из других файлов, с которыми будет слинкован этот.

Date: 2013-02-18 02:55 pm (UTC)
From: [identity profile] evolver.livejournal.com
Да, точно. Я как-то про это не подумал. Выходит, загадок больше не осталось :)
Page generated Dec. 31st, 2025 05:33 pm
Powered by Dreamwidth Studios