Сколько будет (a++ + a++)?

 
1 2 3 4 5 6
+
-
edit
 

trainer

втянувшийся

Rada:
Ничего не понял - держу в руках книгу по ANSI C++, там перечислены все операторы, их степени, приоритеты, и ассоциативность.
 
Что за книга? Потому как я смотрю в стандарт, а там черным по белому написано:
The precedence of operators is not directly specified, but it can be derived from the syntax
 
:)
Во имя Ctrl, Alt и святаго Del. Enter!
 
+
-
edit
 

Balancer

администратор
★★★★★
Язык, в стандарте которого не определены приоритеты - это сильно! :D :
:kosar:
// зелёная, зелёная трава...
 
+
-
edit
 

Balancer

администратор
★★★★★
вот цитата от Отцов:
code text
  1. Операции первичных выражений
  2.  
  3.   () []  .  ->
  4.  
  5. имеют  самый  высокий  приоритет  и  группируются   слева
  6. направо. Унарные операции
  7.  
  8.   *  &  -  !  \^  ++  --  SIZEOF(Имя типа)
  9.  
  10. имеют более низкий приоритет, чем операции первичных выраже-
  11. ний, но более высокий, чем приоритет любой бинарной опера-
  12. ции. Эти операции группируются справа налево. Все бинарные
  13. операции и условная операция (прим. Перевод.: условная опе-
  14. рация группируется справа налево; это изменение внесено в
  15. язык в 1978 г.) группируются слева направо и их приоритет
  16. убывает в следующем порядке:
  17.  
  18.   Бинарные операции:
  19.       *   /   %
  20.       +   -
  21.       >>  <<
  22.       <   >  <=   >=
  23.       ==  !=
  24.       &
  25.       \^
  26.       \!
  27.       &&
  28.     \!\!
  29.       ?:
  30.  
  31.  
  32.  
  33. Все операции присваивания имеют одинаковый приоритет и груп-
  34. пируются справа налево.
  35. Операции присваивания:
  36.   =  +=  -=  *=  ?=  %=  >>=  <<=  &=  \^=  \!=
  37.  
  38. Операция запятая имеет самый низкий приоритет и группируется
  39. слева направо.


 
RU Кирилл #08.07.2004 17:38
+
-
edit
 

Кирилл

втянувшийся

2 Balancer
> Язык, в стандарте которого не определены приоритеты - это сильно!
Это Форт :) Но там-то никаких проблем с порядком выполнения нет - как напишешь, так и выполнится :)
2 Филич
> уважаемый, да вы смысла постфиксных операций не понимаете. именно после операции присванивания ему и место
Смысла операций не понимает прежде всего тот, кто разделяет выполнение одной операции на два шага в разных(!) местах программы. И если для отцов-основателей это было простительно (из-за бедности по железу), то для авторов стандарта C++ - просто глупо. Я не понимаю, почему Вы защищаете откровенный недостаток этого языка.
- Сами понимаете, вселенная-то на моей стороне.
- Вот это мне таким вульгарным и кажется.
 
+
-
edit
 

Balancer

администратор
★★★★★
Кирилл, 08.07.2004 17:38:06 :
Это Форт :) Но там-то никаких проблем с порядком выполнения нет - как напишешь, так и выполнится :)
 


Ну, для постфиксной записи просто понятия приоритета неприменимо :) Как и для префиксной у, скажем, Lisp'а.

>Смысла операций не понимает прежде всего тот, кто разделяет выполнение одной операции на два шага в разных(!) местах программы. И если для отцов-основателей это было простительно (из-за бедности по железу)

Да и во времена отцов-основателей разницы когда делать инкремент, сразу после считывания значения, или через какое-то время, с точки зрения компилятора не было. Да и не разделяли они сами явно этот инкремент на два этапа. Я ж цитировал его выше. А дальше это "после считывания" можно уже двояко читать, либо в элементарную операцию, именно после считывания, либо, либо в конце всех операций. По Оккаму, всё же, первое предпочтительнее :)

А на многом современном железе, так и подавно предпочтительнее. На многих RISC-архитектурах сейчас регистры могут автоматически инкрементиться/декрементиться (или даже меняться на константу, вроде, в ARM - так) после считывания из них значения.
 
?? Филич #09.07.2004 12:43
+
-
edit
 

Филич

втянувшийся

видимо это вопрос уже полурелигиозный :) для меня выполнение постфикса после присваивания вполне естественно и так его всегда и использовал. для вас понятнее интерпретациооное видение. предлагаю дать финальный свисток, который зафиксирует ничью :)
существуют только два типа кораблей: подводные лодки и их цели
 
?? Кирилл #09.07.2004 15:07
+
-
edit
 

Кирилл

втянувшийся

2 Balancer
>Да и во времена отцов-основателей разницы когда делать инкремент, сразу после считывания значения, или через какое-то время, с точки зрения компилятора не было.
По идее да, разве что оптимизации какие-нибудь хитрые нужны. Мне так вообще кажется, что операция ++ обязана своим появлением наличию автоинкрементальной адресации у тогдашних машин с DEC-овской системой команд.
2 Филич
> для меня выполнение постфикса после присваивания вполне естественно и так его всегда и использовал. для вас понятнее интерпретациооное видение.
Нигде, кроме как в среде программистов на Си, такое выполнение не будет естественно. Например, для Форта (а там все операции постфиксные) подобное предположение звучит дико.
- Сами понимаете, вселенная-то на моей стороне.
- Вот это мне таким вульгарным и кажется.
 
?? Филич #09.07.2004 16:22
+
-
edit
 

Филич

втянувшийся

Кирилл
ну если Вам так хочется поспорить...
сравните количество программистов, пишущих на С и С++ и пишущих на Форте.
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

Balancer

администратор
★★★★★
Кирилл, 09.07.2004 15:07:21 :
Мне так вообще кажется, что операция ++ обязана своим появлением наличию автоинкрементальной адресации у тогдашних машин с DEC-овской системой команд.
 


Не-а. Там была только предекрементное и только постинкрементное обращение к памяти :)

Т.е. считать число, выполнив при этом его инкремент было нельзя. И даже по адресу - или только -(R0) или (R0)+ :)
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 09.07.2004 16:22:25 :
Кирилл
ну если Вам так хочется поспорить...
сравните количество программистов, пишущих на С и С++ и пишущих на Форте.
 


Если в Java (кто-нить проверит?) обработка ++ идёт как на PHP/Perl/C#, а не как на C++, то программеры C/C++ будут в меньшинстве :)
 
?? Кирилл #09.07.2004 17:23
+
-
edit
 

Кирилл

втянувшийся

2 Balancer
>Не-а. Там была только предекрементное и только постинкрементное обращение к памяти
>Т.е. считать число, выполнив при этом его инкремент было нельзя. И даже по адресу - или только -(R0) или (R0)+
Я именно это и имел в виду: a:=b[i++] могло в принципе кодироваться в одну команду.

2 Филич
>ну если Вам так хочется поспорить...
>сравните количество программистов, пишущих на С и С++ и пишущих на Форте.
Сравнить самый популярный язык для системного программирования с Фортом? Я ждал этого аргумента :) Только против Вас будет два "но":
1. Легко ли понимают новички систему операций Си?
2. Все ли пишущие на Си считают изврат с операцией ++ еcтественным?
Свою популярность Си вполне заслужил. Да только вот многие его поклонники почему-то умудряются благословлять даже худшие его недостатки (особенно синтаксис), таща их куда попало. А все потому, что для них это "естественно". Зато теперь вынужденно страдают прикладники, которым Си до лампочки, но вот понять, почему в PHP операция присваивания выглядит как =, а равенства как ==, они не могут.
- Сами понимаете, вселенная-то на моей стороне.
- Вот это мне таким вульгарным и кажется.
 
+
-
edit
 

Balancer

администратор
★★★★★
Кирилл, 09.07.2004 17:23:49 :
Я именно это и имел в виду: a:=b[i++] могло в принципе кодироваться в одну команду.
 


Это - да. Тут всё за инкремент переменной сразу после использования, а не потом :) Иначе вместо одной команды получаем две.

>>ну если Вам так хочется поспорить...
>>сравните количество программистов, пишущих на С и С++ и пишущих на Форте.
>Сравнить самый популярный язык для системного программирования с Фортом? Я ждал этого аргумента :) Только против Вас будет два "но"

Ещё третье есть - популярность языка не имеет ничего общего с его восприятием, безглючностью и т.д. и т.п. Иначе мы вынуждены будем считать одним из самых идеологически верных языков, например, Visual Basic :)

А тот же O'Caml или Haskell окажутся в известном месте :)
 
+
-
edit
 

Mishka

модератор
★★★
Balancer>
HardSoft, 05.07.2004 14:14:05 :
да хз.....
ту еще предложили:
 


Какой бред! Пусть выкинут компилер на помойку. Даже старый-старый GCC, не говоря уже об MSVC++, даёт:

<br>main:<br>        pushl   %ebp<br>        movl    %esp, %ebp<br>        subl    $8, %esp<br>        andl    $-16, %esp<br>        subl    $8, %esp<br>        pushl   $12<br>        pushl   $.LC0<br>        call    printf<br>        addl    $16, %esp<br>        movl    %ebp, %esp<br>        popl    %ebp<br>        ret<br>

что??????????? 12???????? :D:D:D

Мде. И в GCC3 также. Ну, бред! :D

Всё, признаЮ свою ошибку и расписываюсь в самоуверенности. Нынешние компиляторы выродились :) (Жаль, MSVC под рукой нет, дома проверю, как там дела обстоят)[»]


Похоже, что тут в стандарте С учтено:

[quote]
©ISO/IEC ISO/IEC 9899:1999 (E)
6.5 Expressions

1. Anexpression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.

2. Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.70)

3.The grouping of operators and operands is indicated by the syntax.71) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

4.Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) are required to have operands that have integer type. These operators return values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.

5. If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

6. The effective type of an object for an access to its stored value is the declared type of the object, if any.72) If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify




70) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

71) The syntax specifies the precedence of operators in the evaluation of an expression, which is the same as the order of the major subclauses of this subclause, highest precedence first. Thus, for example, the expressions allowed as the operands of the binary + operator (6.5.6) are those expressions defined in
6.5.1 through 6.5.6. The exceptions are cast expressions (6.5.4) as operands of unary operators (6.5.3), and an operand contained between any of the following pairs of operators: grouping parentheses () (6.5.1), subscripting brackets [] (6.5.2.1), function-call parentheses () (6.5.2.2), and the conditional operator ?: (6.5.15). Within each major subclause, the operators have the same precedence. Left- or right-associativity is indicated in each subclause by the syntax for the expressions discussed therein.

72) Allocated objects have no declared type.


§6.5 Language 67
[/quote]

Хотя, тут надо еще посмотреть - как именно сайд-эффекты могут откладываться.
 
+
-
edit
 

Mishka

модератор
★★★
Вот программка :P :
code c
  1. #include <stdio.h>
  2. int main( int argc, char* argv[ ] )
  3. {
  4.         int a = 5;
  5.         volatile int b = 5;
  6.         int c = 5;
  7.         volatile int d = 5;
  8.         register int e = 5;
  9.         register int f = 5;
  10.  
  11.         int a1, b1, c1, d1, e1, f1;
  12.  
  13.         a1 = a++ + a++;
  14.         b1 = b++ + b++;
  15.         c1 = ++c + ++c;
  16.         d1 = ++d + ++d;
  17.         e1 = e++ + e++;
  18.         f1 = ++f + ++f;
  19.         printf( "a=%d, b=%d, c=%d, d=%d, e=%d, f=%d\n", a, b, c, d, e, f );
  20.         printf( "a1=%d, b1=%d, c1=%d, d1=%d, e1=%d, f1=%d\n", a1, b1, c1, d1, e1, f1 );
  21.  
  22.         a = 5; b = 5; c = 5; d = 5; e = 5; f = 5;
  23.         a = a++ + a++;
  24.         b = b++ + b++;
  25.         c = ++c + ++c;
  26.         d = ++d + ++d;
  27.         e = e++ + e++;
  28.         f = ++f + ++f;
  29.         printf( "a=%d, b=%d, c=%d, d=%d, e=%d, f=%d\n", a, b, c, d, e, f );
  30.  
  31.  
  32.         return 0;
  33. }


Вот результат прогона на .Net Studio 2003:
C:\Tests\plpl\plpl\Debug>plpl
a=7, b=7, c=7, d=7, e=7, f=7
a1=10, b1=10, c1=14, d1=14, e1=10, f1=14
a=12, b=12, c=14, d=14, e=12, f=14

C:\Tests\plpl\plpl\Debug>
 

Вот результат прогона на gcc v 3.4.0:
evsmi01392-3046-nposuse:~/tests> ./t0005
a=7, b=6, c=7, d=7, e=7, f=7
a1=10, b1=10, c1=14, d1=13, e1=10, f1=14
a=12, b=10, c=14, d=13, e=12, f=14
evsmi01392-3046-nposuse:~/tests> gcc -v
Reading specs from /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.0/specs
Configured with: ./configure
Thread model: posix
gcc version 3.4.0
 


Вот результат прогона на gcc v 3.4.1:
evsmi01suseentp-1:~/tests> ./t0005
a=7, b=6, c=7, d=7, e=7, f=7
a1=10, b1=10, c1=14, d1=13, e1=10, f1=14
a=12, b=10, c=14, d=13, e=12, f=14
evsmi01suseentp-1:~/tests> gcc -v
Reading specs from /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.1/specs
Configured with: ./configure
Thread model: posix
gcc version 3.4.1
evsmi01suseentp-1:~/tests>
 


 
+
-
edit
 

Mishka

модератор
★★★
Balancer>[quote|Филич, 06.07.2004 12:57:21 :]а с чего ты решил, что постфиксная операция должна выполняться до конца выражения? имхо все верно :)[/quote]
Balancer>Да читал когда-то. М.б. даже у того же Кернигана с Ричи :D
Вообще, формально работу ++ описывают именно как взять старое значение и увеличить переменную. Ну и, хоть не указывается, но по логике-то (и по реализации ++ в других языках!) увеличивается тут же, а не после завершения всего вычисления.[»]


Не-а - вот тебе из ANSI, ISO, IEC C standard, publication 9899:
The result of the postfix ++ operator is the value of the operand. After the result is
obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate
type is added to it.) See the discussions of additive operators and compound assignment
for information on constraints, types, and conversions and the effects of operations on
pointers. The side effect of updating the stored value of the operand shall occur between
the previous and the next sequence point.
 
 
+
-
edit
 

Mishka

модератор
★★★
Орлы!
>Вы пытаетесь говорить что как-то вычислять правильно, а как-то нет только потому, что так делает ваш любимый компилятор и подстраиваете свое объяснение под его поведение.
В стандарте же ясно написано - behavior is unspecified.
Что мешает переписать это выражение так, чтобы behavior был specified?

Изменение объекта - побочный эффект(side effect). Порядок проявления побочных эффектов не определен. Определено только, что в sequence point все побочные эффекты предыдущих вычислений проявились, а ни один побочный эффект последующих - нет.

Unspecified behavior - похоже на implementation-defined behavior, но при этом эта самая implementation не обязана документировать это самое behavior. :)[»]

О, полностью согласен.
 
+
-
edit
 

Balancer

администратор
★★★★★
>Вы пытаетесь говорить что как-то вычислять правильно, а как-то нет только потому, что так делает ваш любимый компилятор и подстраиваете свое объяснение под его поведение.

Не надо обобщать :) Потому что мой любимый компилятор из вышеупомянутых как раз поступает неправильно и не так, как все другие :D

Просто кроме формальных рукоумывательств есть ещё здравый смысл.

Вот о нём и спор.
 
RU ДСота #06.10.2004 10:02  @HardSoft#05.07.2004 12:27
+
-
edit
 
HardSoft>для тех кто шарит в программировании вопрос:

a=5;
a=5++ + 5++;

сколько будет? :))))[»]


будет 10!

А ++а + ++а = 12
 
+
-
edit
 

Balancer

администратор
★★★★★
Собственно, только сейчас сформулировал, что мне не нравится в поведении C/C++ в отношении сабжевого пример. В ++ мы тут имеем неприкрытый side-effect. Один ++ влияет на значение другого.

Без side-effect результат a = i++ + i++; должен быть точно равен результату:
b = i++;
c = i++;
a = b + c;

Так что, как ни крути, а имеем чудовищную языковую корявость. Введение второго ++ меняет результат первого.
 
+
-
edit
 

Mishka

модератор
★★★
Э, не совсем корявость. Тут скорее как рассматривать вычисление выражения. Скажем, Алгол 68 прямо говорит, что вычисления операндов в выражении идёт так, как будто в математике — все одновременно. С/С++ это неявно взял оттуда. Поэтому и появились sequence point — точки синхронизации параллелизма.
В выражении
a = i++ + i++;
; как раз и есть точка синхронизации.
А в последовательности
b = i++;
c = i++;
a = b + c;

Их аж три.

Аналог будет, если по всём правилам будет:
i1 = i;
i2 = i;
a = i1 + i2;
// sequence point — начинают проявлятся будущие side effects.

i1++;
i = i1;
i2++;
i = i2;

Но так почти никто не делает.
 
1 2 3 4 5 6

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru