avva: (Default)
[personal profile] avva
Гуляя по исходникам ядра Линукса в поисках информации о том, как в нём устроены 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;

Date: 2003-09-30 01:08 am (UTC)
From: [identity profile] oblomov-jerusal.livejournal.com
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 должно делать то же самое?

Date: 2003-09-30 01:10 am (UTC)
From: [identity profile] oblomov-jerusal.livejournal.com
В смысле, x || y

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

Date: 2003-09-30 01:19 am (UTC)
From: [identity profile] avva.livejournal.com
Да, спасибо. Как раз 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)

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

Date: 2003-09-30 01:28 am (UTC)
From: [identity profile] muchacho.livejournal.com
Из 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."

Date: 2003-09-30 01:11 am (UTC)
From: [identity profile] pishi-chitai.livejournal.com
MSVC такого точно не позволяет.

Date: 2003-09-30 01:18 am (UTC)
From: [identity profile] anton.livejournal.com
Это собственные расширения gcc. В стандарте ничего такого не сказано, и в msvc последнем это не работает.

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

Date: 2003-09-30 01:21 am (UTC)
From: [identity profile] avva.livejournal.com
Не очень я тогда понимаю, зачем авторам ядра Линукса с этим баловаться — не то чтобы это так уж незаменимо было...

Впрочем, может, это у меня BSDшные привычки сказываются, там стараются локализовать как можно более тщательно gcc-specific code.

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

Date: 2003-09-30 02:00 am (UTC)
From: [identity profile] bobuk.livejournal.com
Все проще - у gcc < 3.x.x в операторе 'x?a:b' еще небыло "интеллектуальной" оптимизации кода, а операция 'x?:b' оптимизировалась.

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

Date: 2003-09-30 02:07 am (UTC)
From: [identity profile] homa.livejournal.com
Я всегда не доверял "интеллектуальной оптимизации" (почти Ц) :)

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

Date: 2003-09-30 02:01 am (UTC)
From: [identity profile] homa.livejournal.com
Хуже того, выражение A ? A : B, по-видимому, не обязательно эквивалентно выражению A ? : B.
Например, (i++) ? (i++) : i и (i++) ? : i.

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

Date: 2003-09-30 02:13 am (UTC)
From: [identity profile] avva.livejournal.com
Да, это ясно ;)
Короче, только приключения на свою голову придумывают.

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

Date: 2003-09-30 03:05 am (UTC)
From: [identity profile] bolk.livejournal.com
Вообще говоря, я мягким место чувствую, что вот так на "A ? A : B" суперпозицию нельзя навешивать.

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

Date: 2003-09-30 05:35 am (UTC)
From: [identity profile] arbat.livejournal.com

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

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


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

Date: 2003-09-30 05:47 am (UTC)
From: [identity profile] homa.livejournal.com
В вашем случае результат будет таким: i = 3, j = 2.

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

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

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

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

Date: 2003-09-30 06:05 am (UTC)
From: [identity profile] homa.livejournal.com
Даже, наверно, i = 2, j = 1. Проверить не на чем.

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

Date: 2003-09-30 12:12 pm (UTC)
From: [identity profile] arbat.livejournal.com

Так, наверное или точно? И как узнать?
"Проверить" - это не разговор.

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

Date: 2003-10-01 12:21 am (UTC)
From: [identity profile] homa.livejournal.com
А вы, прошу пардону, спорите с моей первоначальной репликой? Или просто решили мне экзамен устроить? :) Придумать произвольную ситуацию, потребовать ее "в уме" проиграть, а потом еще и настаивать на точности? Как говаривал кто-то из физиков, "мой книжный шкаф знает больше меня, но физик не он, а я".

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

Date: 2003-10-01 04:46 pm (UTC)
From: [identity profile] arbat.livejournal.com
Нет, не беспокойтесь, я Вас экзаменовать не собирался.
Можете посмотреть обсуждение в паралелльном треде.
Суть в том, что конструкция, в которой возможны сомнения, а необходимости нету никакой - не должна употребляться вообще.

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

Date: 2003-09-30 09:15 am (UTC)
From: [identity profile] dvv.livejournal.com
Никакого - это не является программой на 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.

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

Date: 2003-09-30 12:10 pm (UTC)
From: [identity profile] arbat.livejournal.com

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

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

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

Date: 2003-09-30 12:21 pm (UTC)
From: [identity profile] dvv.livejournal.com
Хм? Мне потребовалось заглянуть в стандарт чтобы привести цитату, chapter и verse, что никак не говорит о моём немедленном знании или незнании сути данного конкретного вопроса. Что же касается моего стиля кодирования, так я стараюсь, чтобы он был максимально прозрачным и однозначным даже для кодеров с весьма общим представлением о языке, чтобы у любителей гадать о моих намерениях было как можно меньше материала для их любимого занятия.

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

Date: 2003-09-30 12:27 pm (UTC)
From: [identity profile] arbat.livejournal.com
Вы хотите сказать, что были абсолютно, на 100% - уверены, что нету никаких проблем? :-)



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

Date: 2003-09-30 12:31 pm (UTC)
From: [identity profile] dvv.livejournal.com
Я хочу сказать, что я абсолютно, на 100% был уверен, что с точки зрения языка никаких проблем в примере не было.

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

Date: 2003-09-30 12:24 pm (UTC)
From: [identity profile] dvv.livejournal.com
В догонку:

более того, кодер, который при мне демонстрирует такой код в процессе выполнения своих служебных обязанностей, вполне рискует.

Date: 2003-09-30 10:26 am (UTC)
From: [identity profile] vzaliva.livejournal.com
я посмотрел по стандарту C99 - такое запрещено.

Date: 2003-09-30 10:41 am (UTC)
From: [identity profile] avva.livejournal.com
Спасибо!

Date: 2003-10-01 06:09 am (UTC)
From: [identity profile] ex-innin997.livejournal.com
это логично, ведь condition ? expression : expression это условный оператор, возвращающий какое-либо значение. В Perl тоже работает
print 1 + (1 ? 1 : 3);

Date: 2003-10-01 06:15 am (UTC)
From: [identity profile] ex-innin997.livejournal.com
прошу прощения, мой комментарий совсем не по теме вашего рассуждения. Просто я читал это обсуждение пару дней назад, и был увлечён собственными мыслями.
В Perl без одного операнда $a = ($b ? : $d); не работает

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
2829 30 31   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 1st, 2026 09:25 pm
Powered by Dreamwidth Studios