?

Log in

программистское: C, Unix - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

программистское: C, Unix [сент. 30, 2003|10:52 am]
Anatoly Vorobey
Гуляя по исходникам ядра Линукса в поисках информации о том, как в нём устроены real-time signals (см. 'man 7 signal', если вы не знаете, что это такое), я обнаружил случайно весьма удивительную конструкцию в C:

Оператор условного выбора ?:, но без второго операнда. То есть вместо обычного, скажем,

a = b ? c : d;

(что означает: если b, то присвоить a=c; иначе присвоить a=d), пишется, например, так:

a = b ? : d;

По контексту становится ясно, что это означает: если b, то a=b; иначе a=d.

(кстати, весьма неинтуитивно; самым очевидным кажется такая интерпретация: если b, то a не меняется, иначе a=d. Но, конечно, на самом деле такая интерпретация невозможна, т.к. согласно семантике языка выражение (b ? : d) должно иметь какое-то определённое значение)

Так вот, я такого никогда в жизни не видел, и не подозревал даже, что так можно писать. Теперь мне интересно, это разрешено каким-то стандартом, или это какое-то расширение gcc? Знает ли кто?

Пример "живого" использования в исходнике ядра Линукса см. например в файле net/ipv4/tcp.c, там их шесть штук (в 2.4.20 по крайней мере). Например:

val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time)/HZ;
СсылкаОтветить

Comments:
From: oblomov_jerusal
2003-09-30 01:08 am
File: gcc-3.3.info,  Node: Conditionals,  Next: Long Long,  Prev: Lvalues,  Up:\ C Extensions
                                                                                
Conditionals with Omitted Operands
==================================
                                                                                
The middle operand in a conditional expression may be omitted.  Then if
the first operand is nonzero, its value is the value of the conditional
expression.
                                                                                
   Therefore, the expression
                                                                                
     x ? : y
                                                                                
has the value of `x' if that is nonzero; otherwise, the value of `y'.
                                                                                
   This example is perfectly equivalent to
                                                                                
     x ? x : y



Вроде бы x && y должно делать то же самое?
(Ответить) (Thread)
From: oblomov_jerusal
2003-09-30 01:10 am
В смысле, x || y
(Ответить) (Thread)
[User Picture]From: avva
2003-09-30 01:19 am

Re: программистское: C, Unix

Да, спасибо. Как раз gcc.info у меня под руками не оказалось почему-то.
Если не ошибаюсь, значение x||y не гарантировано ==x в случае, если x не равно 0; всё, что гарантировано, это то, что only x is evaluated and the result evaluates as true (т.е. компилятор может выбрать ставить всегда 1 в качестве результата в таких случаях). Впрочем, моя память, возможно, меня подводит в этом пункте.

(а вот в перле, скажем, x||y всегда равно x, если x evaluates as true)
(Ответить) (Parent) (Thread)
[User Picture]From: muchacho
2003-09-30 01:28 am

Re: программистское: C, Unix

Из MSDN/C Language Reference:
"The logical-OR operator performs an inclusive-OR operation on its operands. The result is 0 if both operands have 0 values. If either operand has a nonzero value, the result is 1."
(Ответить) (Parent) (Thread)
[User Picture]From: pishi_chitai
2003-09-30 01:11 am
MSVC такого точно не позволяет.
(Ответить) (Thread)
[User Picture]From: anton
2003-09-30 01:18 am
Это собственные расширения gcc. В стандарте ничего такого не сказано, и в msvc последнем это не работает.
(Ответить) (Thread)
[User Picture]From: avva
2003-09-30 01:21 am

Re: программистское: C, Unix

Не очень я тогда понимаю, зачем авторам ядра Линукса с этим баловаться — не то чтобы это так уж незаменимо было...

Впрочем, может, это у меня BSDшные привычки сказываются, там стараются локализовать как можно более тщательно gcc-specific code.
(Ответить) (Parent) (Thread)
[User Picture]From: bobuk
2003-09-30 02:00 am

Re: программистское: C, Unix

Все проще - у gcc < 3.x.x в операторе 'x?a:b' еще небыло "интеллектуальной" оптимизации кода, а операция 'x?:b' оптимизировалась.
(Ответить) (Parent) (Thread)
[User Picture]From: homa
2003-09-30 02:07 am

Re: программистское: C, Unix

Я всегда не доверял "интеллектуальной оптимизации" (почти Ц) :)
(Ответить) (Parent) (Thread)
[User Picture]From: homa
2003-09-30 02:01 am

Re: программистское: C, Unix

Хуже того, выражение A ? A : B, по-видимому, не обязательно эквивалентно выражению A ? : B.
Например, (i++) ? (i++) : i и (i++) ? : i.
(Ответить) (Parent) (Thread)
[User Picture]From: avva
2003-09-30 02:13 am

Re: программистское: C, Unix

Да, это ясно ;)
Короче, только приключения на свою голову придумывают.
(Ответить) (Parent) (Thread)
[User Picture]From: bolk
2003-09-30 03:05 am

Re: программистское: C, Unix

Вообще говоря, я мягким место чувствую, что вот так на "A ? A : B" суперпозицию нельзя навешивать.
(Ответить) (Parent) (Thread)
[User Picture]From: arbat
2003-09-30 05:35 am

Re: программистское: C, Unix


Замечательно. A теперь скажите, какой результат будет у

int i = 1;
int j = i++ ? i++ : i;


(Ответить) (Parent) (Thread)
[User Picture]From: homa
2003-09-30 05:47 am

Re: программистское: C, Unix

В вашем случае результат будет таким: i = 3, j = 2.

В случае же
int i = 1;
int j = i++ ? : i;

результат будет несколько иным: i = 2, j = 2.

Т.е., во втором случае пропущенное выражение вновь вычисляться не будет -- во всяком случае, надеюсь на это. Иначе это уже не С, а, простите, Васик какой-то.

(Ответить) (Parent) (Thread)
[User Picture]From: homa
2003-09-30 06:05 am

Re: программистское: C, Unix

Даже, наверно, i = 2, j = 1. Проверить не на чем.
(Ответить) (Parent) (Thread)
[User Picture]From: arbat
2003-09-30 12:12 pm

Re: программистское: C, Unix


Так, наверное или точно? И как узнать?
"Проверить" - это не разговор.
(Ответить) (Parent) (Thread)
[User Picture]From: homa
2003-10-01 12:21 am

Re: программистское: C, Unix

А вы, прошу пардону, спорите с моей первоначальной репликой? Или просто решили мне экзамен устроить? :) Придумать произвольную ситуацию, потребовать ее "в уме" проиграть, а потом еще и настаивать на точности? Как говаривал кто-то из физиков, "мой книжный шкаф знает больше меня, но физик не он, а я".
(Ответить) (Parent) (Thread)
[User Picture]From: arbat
2003-10-01 04:46 pm

Re: программистское: C, Unix

Нет, не беспокойтесь, я Вас экзаменовать не собирался.
Можете посмотреть обсуждение в паралелльном треде.
Суть в том, что конструкция, в которой возможны сомнения, а необходимости нету никакой - не должна употребляться вообще.
(Ответить) (Parent) (Thread)
[User Picture]From: dvv
2003-09-30 09:15 am

Re: программистское: C, Unix

Никакого - это не является программой на C :-)

А так - j будет равно 2, i будет равно 3. Стандарта C под рукой нет, а в C++ в 5.16/1 явно сказано, что все side effects of the first expression [...] happen before the second or third expression is evaluated.
(Ответить) (Parent) (Thread)
[User Picture]From: arbat
2003-09-30 12:10 pm

Re: программистское: C, Unix


Отлично :-) Однако, Вам потребовалось заглянуть в стандарт, чтобы проверить порядок выполнения операторов. При этом Вы повели себя как интеллигентный человек, который знает, что порядок вообще говоря может быть всякий, что иногда он задан стандартом, а иногда нет, и который знает, куда посмотреть и держит хоть один из стандартов "под руками". Поздравляю, Вы входите в 1% людей, которые так себя ведут.

Беда в том, что Ваш код потом будет изучаться и, возможно, "улучшаться" другими, которые с вероятностью 99% не войдут в Ваш интеллигентский 1% :-)
Мораль - так писать не надо, и сокращенной версией пользоваться - тоже. Экономия копеечная, а потом кто-то в темном лесу напорется на сук.

(Ответить) (Parent) (Thread)
[User Picture]From: dvv
2003-09-30 12:21 pm

Re: программистское: C, Unix

Хм? Мне потребовалось заглянуть в стандарт чтобы привести цитату, chapter и verse, что никак не говорит о моём немедленном знании или незнании сути данного конкретного вопроса. Что же касается моего стиля кодирования, так я стараюсь, чтобы он был максимально прозрачным и однозначным даже для кодеров с весьма общим представлением о языке, чтобы у любителей гадать о моих намерениях было как можно меньше материала для их любимого занятия.
(Ответить) (Parent) (Thread)
[User Picture]From: arbat
2003-09-30 12:27 pm

Re: программистское: C, Unix

Вы хотите сказать, что были абсолютно, на 100% - уверены, что нету никаких проблем? :-)



(Ответить) (Parent) (Thread)
[User Picture]From: dvv
2003-09-30 12:31 pm

Re: программистское: C, Unix

Я хочу сказать, что я абсолютно, на 100% был уверен, что с точки зрения языка никаких проблем в примере не было.
(Ответить) (Parent) (Thread)
[User Picture]From: dvv
2003-09-30 12:24 pm

Re: программистское: C, Unix

В догонку:

более того, кодер, который при мне демонстрирует такой код в процессе выполнения своих служебных обязанностей, вполне рискует.
(Ответить) (Parent) (Thread)
[User Picture]From: vzaliva
2003-09-30 10:26 am
я посмотрел по стандарту C99 - такое запрещено.
(Ответить) (Thread)
[User Picture]From: avva
2003-09-30 10:41 am
Спасибо!
(Ответить) (Parent) (Thread)
From: ex_innin997
2003-10-01 06:09 am
это логично, ведь condition ? expression : expression это условный оператор, возвращающий какое-либо значение. В Perl тоже работает
print 1 + (1 ? 1 : 3);
(Ответить) (Thread)
From: ex_innin997
2003-10-01 06:15 am
прошу прощения, мой комментарий совсем не по теме вашего рассуждения. Просто я читал это обсуждение пару дней назад, и был увлечён собственными мыслями.
В Perl без одного операнда $a = ($b ? : $d); не работает
(Ответить) (Parent) (Thread)