Discussion:
Зачем "do { ... } while(0)" ?
(слишком старое сообщение для ответа)
Serguei E. Leontiev
2014-05-31 18:51:41 UTC
Permalink
Всем привет,

Вот антиресно, зачем в некоторых POSIX системах с маниакальным упорством
используют эту конструкцию в макросах? Hапример:

#define _atomic_spin_lock_irqsave(l,f) do { \
raw_spinlock_t *s = ATOMIC_HASH(l); \
local_irq_save(f); \
__raw_spin_lock(s); \
} while(0)
--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
<http://www.cryptopro.ru>
Valentin Nechayev
2014-05-31 19:07:55 UTC
Permalink
SEL> Вот антиресно, зачем в некоторых POSIX системах с маниакальным упорством
SEL> используют эту конструкцию в макросах? Hапример:

SEL> #define _atomic_spin_lock_irqsave(l,f) do { \
SEL> raw_spinlock_t *s = ATOMIC_HASH(l); \
SEL> local_irq_save(f); \
SEL> __raw_spin_lock(s); \
SEL> } while(0)

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

А что Вы предлагаете взамен?


--netch--
Nickita A Startcev
2014-05-31 21:26:40 UTC
Permalink
Привет, Valentin !


31 May 14 , 23:07 Valentin Nechayev писал к "Serguei E. Leontiev":

SEL>> Вот антиресно, зачем в некоторых POSIX системах с маниакальным
SEL>> упорством используют эту конструкцию в макросах? Hапример:

SEL>> #define _atomic_spin_lock_irqsave(l,f) do { \
SEL>> raw_spinlock_t *s = ATOMIC_HASH(l); \
SEL>> local_irq_save(f); \
SEL>> __raw_spin_lock(s); \
SEL>> } while(0)

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

VN> А что Вы предлагаете взамен?

а в чем будет разница между
do { foo(); bar(); zu(); blabla() } while(0);
и
{ foo(); bar(); zu(); blabla() };
?

. С уважением, Hикита.
icq:240059686, lj-user:nicka_startcev
... Ogre-ссивность
Serguei E. Leontiev
2014-05-31 22:43:17 UTC
Permalink
Привет Hикита,

От 1 июня 2014 г., 1:26:40 в fido7.ru.unix.prog ты писал:
SEL>>> Вот антиресно, зачем в некоторых POSIX системах с
SEL>>> маниакальным упорством используют эту конструкцию в
SEL>>> макросах? Hапример:
SEL>>> #define _atomic_spin_lock_irqsave(l,f) do { \
SEL>>> raw_spinlock_t *s = ATOMIC_HASH(l); \
SEL>>> local_irq_save(f); \
SEL>>> __raw_spin_lock(s); \
SEL>>> } while(0)
VN>> Очевидно, чтобы она для компилятора выглядела синтаксически
VN>> точно так же, как одиночный оператор, что сохраняет границы
VN>> блоков.
VN>> А что Вы предлагаете взамен?

В данном случае, я не предлагаю, я думаю, что делать с параноидальными
компиляторами, которым "while(0)" не по нраву.

NS> а в чем будет разница между
NS> do { foo(); bar(); zu(); blabla() } while(0);
NS> и
NS> { foo(); bar(); zu(); blabla() };

Если по совету Евгения из соседнего ответа заглянуть в "man 9 style" на
FreeBSD, то можно будет лицезреть "стильную" конструкцию:

if(test)
stmt; /* <- разница вот здесь */
else if(bar) {
stmt;
stmt;
} else
stmt;

Это не мой стиль, поэтому, я запямятовал, что в стандарте, кроме
операторов безусловного перехода, есть только два оператора с ';'.

Оператор выражения:
expression(opt) ;

Оператор do:
do statement while ( expression ) ;

Вот и лажанулся.

--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Valentin Nechayev
2014-06-01 04:39:17 UTC
Permalink
VN>>> А что Вы предлагаете взамен?
SEL> В данном случае, я не предлагаю, я думаю, что делать с параноидальными
SEL> компиляторами, которым "while(0)" не по нраву.

Или выключать паранойю в этом конкретном месте, или менять компилятор.
Потому что если компилятор некоего языка жалуется на средство лечения
кривизны этого языка, такому компилятору место на помойке.

SEL> Это не мой стиль, поэтому, я запямятовал, что в стандарте, кроме
SEL> операторов безусловного перехода, есть только два оператора с ';'.

Вообще-то в Си _все_ операторы с ';', в том смысле, что точка с
запятой завершает оператор. Вот блоки её не требуют после себя, и это
ляп дизайна.


--netch--
Serguei E. Leontiev
2014-06-01 12:41:48 UTC
Permalink
Привет Валентин,

От 1 июня 2014 г., 8:39:17 в fido7.ru.unix.prog ты писал:
VN>>>> А что Вы предлагаете взамен?
SEL>> В данном случае, я не предлагаю, я думаю, что делать с
SEL>> параноидальными компиляторами, которым "while(0)" не по
SEL>> нраву.
VN> Или выключать паранойю в этом конкретном месте, или менять
VN> компилятор. Потому что если компилятор некоего языка жалуется
VN> на средство лечения кривизны этого языка, такому компилятору
VN> место на помойке.

Вот, вечно, вы хирурги так: "Резать! Резать!..."

SEL>> Это не мой стиль, поэтому, я запямятовал, что в стандарте,
SEL>> кроме операторов безусловного перехода, есть только два
SEL>> оператора с ';'.
VN> Вообще-то в Си _все_ операторы с ';', в том смысле, что точка с
VN> запятой завершает оператор. Вот блоки её не требуют после себя,

Или, так, но это не объясняет, почему для "do { ... } while(0)" нет
альтернативы. Если строить описательные конструкции на человеческом
языке, то операторы перехода, оператор выражения и оператор do
завершаются ";", составной оператор завершается "}", а остальные
операторы завершаются другим оператором.

Я в наречиях западных англосакских варваров слаб, но в ISO/IEC 9899:2011
есть место, практически без единого слова, которое и процитирую, см.
6.8.3, 6.8.5 и 6.8.6:

A.2.3 Statements

(6.8) statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement

(6.8.1) labeled-statement:
identifier : statement
case constant-expression : statement
default : statement

(6.8.2) compound-statement:
{ block-item-listopt }

(6.8.2) block-item-list:
block-item
block-item-list block-item

(6.8.2) block-item:
declaration statement

(6.8.3) expression-statement:
expression(opt) ;

(6.8.4) selection-statement:
if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement

(6.8.5) iteration-statement:
while ( expression ) statement
do statement while ( expression ) ;
for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
for ( declaration expression(opt) ; expression(opt) ) statement

(6.8.6) jump-statement:
goto identifier ;
continue ;
break ;
return expression(opt) ;

--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Valentin Nechayev
2014-06-04 05:30:09 UTC
Permalink
SEL> Или, так, но это не объясняет, почему для "do { ... } while(0)" нет
SEL> альтернативы. Если строить описательные конструкции на человеческом
SEL> языке, то операторы перехода, оператор выражения и оператор do
SEL> завершаются ";", составной оператор завершается "}", а остальные
SEL> операторы завершаются другим оператором.

Обратите внимание: после обычного compound statement не положено
ставить ';' - она может поменять смысл программы! А именно это
получается, если бы вместо X() поставить {Y,Z} без while(0). То есть
имея, например,

if (cond)
X();
else
XX();

в случае подстановки без while(0) получаем:

if (cond)
{Y;Z};
else
XX();

Это не распарсится правильно, потому что {Y;Z} сработает как условие
по then, затем встретится ';' и поиск ветки else будет закончен,
потому что грамматика для if-конструкции закончилась. Далее, если этот
else не к чему отнести, будет ошибка парсинга, а если есть к чему
снаружи - будет отнесено неправильно (и это ещё одна причина, почему
стили настаивают, что все хоть как-то сложные конструкции заключаются
в {}).

Зато при правильной подстановке получим

if (cond)
do {Y;Z;} while(0);
else
XX();

и таких проблем не будет.

SEL> Я в наречиях западных англосакских варваров слаб, но в ISO/IEC 9899:2011
SEL> есть место, практически без единого слова, которое и процитирую, см.
SEL> 6.8.3, 6.8.5 и 6.8.6:

Вот и проанализируйте его с точки зрения, когда в

SEL> (6.8.4) selection-statement:
SEL> if ( expression ) statement
SEL> if ( expression ) statement else statement
SEL> switch ( expression ) statement

окажется

if ( expression) statement statement else statement

Результат, думаю, очевиден.

Да, вот такую дрянь подсунули авторы синтаксиса Си и все его
последователи (включая Java, C# и ещё тысячи их). Вирт эту ловушку
заметил раньше и в Модуле потребовал обязательность блоковых скобок.
Ещё мне очень нравится вариант синтаксиса встроенных скриптов SIP
Express Router, в остальном C-подобный:

if (condition) { statement-list }
[ elsif (condition) { statement-list } ] ...
[ else { statement-list } ]
;

то есть ';' обязательна для завершения всей конструкции и не может
встретиться раньше. В этой схеме можно и сделать явный блок:

{ statement-list };

или, для ясности,

do { statement-list };

путаницы с do-while не возникнет.


--netch--
Serguei E. Leontiev
2014-06-04 17:34:56 UTC
Permalink
Валентин, привет,
Post by Valentin Nechayev
Обратите внимание: после обычного compound statement не положено
ставить ';' - она может поменять смысл программы! А именно это
получается, если бы вместо X() поставить {Y,Z} без while(0). То есть
имея, например,
if (cond)
X();
else
XX();
if (cond)
{Y;Z};
else
XX();
Это не распарсится правильно, потому что {Y;Z} сработает как условие
по then, затем встретится ';' и поиск ветки else будет закончен,
потому что грамматика для if-конструкции закончилась. Далее, если этот
else не к чему отнести, будет ошибка парсинга, а если есть к чему
снаружи - будет отнесено неправильно (и это ещё одна причина, почему
Hе существует синтаксически корректных программ о которых ты пишешь.
Post by Valentin Nechayev
Post by Serguei E. Leontiev
if ( expression ) statement else statement
Между 'if()' и 'else' может быть только один оператор. Очевидно, в данном
случае, он не может быть оператором перехода, выражения, оператором do и
составным оператором, таким образом, вывод '}' и '; ' это уже не один
оператор.
Post by Valentin Nechayev
Вот и проанализируйте его с точки зрения, когда в
Post by Serguei E. Leontiev
if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement
окажется
if ( expression) statement statement else statement
Результат, думаю, очевиден.
Hе понял, мне кажется, что стандарт требует возникновения синтаксической
ошибки в этом очевидном случае, или я не прав?

Возможно ты имел ввиду:

if ( expression ) if ( expression ) statement else statement
--
Успехов, Сергей Леонтьев, <http://www.cryptopro.ru> (NewsTap)
Valentin Nechayev
2014-06-04 18:34:15 UTC
Permalink
SEL> Hе существует синтаксически корректных программ о которых ты пишешь.

В каком смысле?
Post by Valentin Nechayev
Post by Serguei E. Leontiev
if ( expression ) statement else statement
SEL> Между 'if()' и 'else' может быть только один оператор. Очевидно, в данном
SEL> случае, он не может быть оператором перехода, выражения, оператором do и
SEL> составным оператором, таким образом, вывод '}' и '; ' это уже не один
SEL> оператор.

Именно! А нужно, чтобы там был один оператор. Для этого и нужны хитрые
скобки в виде do{...}while(0).
Post by Valentin Nechayev
if ( expression) statement statement else statement
Результат, думаю, очевиден.
SEL> Hе понял, мне кажется, что стандарт требует возникновения синтаксической
SEL> ошибки в этом очевидном случае, или я не прав?

Да, требует.
А надо, чтобы скомпилировалось и сработало как заказывали.

SEL> Возможно ты имел ввиду:

SEL> if ( expression ) if ( expression ) statement else statement

Hет, для примера это лишнее.


--netch--
Serguei E. Leontiev
2014-06-05 07:07:45 UTC
Permalink
Привет Валентин,

От 4 июня 2014 г., 22:34:15 в fido7.ru.unix.prog ты писал:
SEL>> Hе существует синтаксически корректных программ о которых
SEL>> ты пишешь.
VN> В каком смысле?

Hе существует синтаксически корректных программ с изменённым смыслом, в
смысле положения "...если есть к чему снаружи - будет отнесено
неправильно..." из рассуждения о возможном изменении смысла:

"... ставить ';' - она может поменять смысл программы! ...
... по then, затем встретится ';' и поиск ветки else будет закончен,
потому что грамматика для if-конструкции закончилась. Далее, если этот
else не к чему отнести, будет ошибка парсинга, а если есть к чему
снаружи - будет отнесено неправильно ..."
:)

Хотя компиляторы всякие бывали, а может ещё и бывают.

Hу, да ладно, спасибо за разъяснения в деле "do { ... } while(0)".

--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Eugene Grosbein
2014-05-31 22:12:12 UTC
Permalink
31 май 2014, суббота, в 21:51 NOVT, Сергей Ефимович Лео нтьев написал(а):

СЕЛн> Вот антиресно, зачем в некоторых POSIX системах с маниакальным упорством
СЕЛн> используют эту конструкцию в макросах? Hапример:

СЕЛн> #define _atomic_spin_lock_irqsave(l,f) do { \
СЕЛн> raw_spinlock_t *s = ATOMIC_HASH(l); \
СЕЛн> local_irq_save(f); \
СЕЛн> __raw_spin_lock(s); \
СЕЛн> } while(0)

В man 9 style на фре есть объяснение, зачем:
чтобы можно было писать потом, не используя фигурные скобки:

if (condition)
_atomic_spin_lock_irqsave(l,f);

Eugene
Loading...