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

 
1 2 3 4 5 6
+
-
edit
 

Balancer

администратор
★★★★★
Zeus, 05.07.2004 21:39:26 :
>Да сам C++ в наше время уже моветон.
Он с рождения такой :P
 


Раньше с альтернативами не густо было :)
Машины слабенькие были...
 

Rada

опытный

code text
  1. class Integer
  2. {
  3. public:
  4.         Integer(int Num) : m_iNum(Num) {}
  5.         operator int() { return m_iNum; }
  6.  
  7.         Integer operator+(const Integer& I) { return m_iNum + I.m_iNum; }
  8.         Integer operator++() { return m_iNum++; }
  9.  
  10. private:
  11.         int m_iNum;
  12. };
  13.  
  14. int main(int argc, char* argv[])
  15. {
  16.         Integer a = 5;
  17.  
  18.         int b = a++ + a++;
  19.  
  20.         return 0;
  21. }
Здесь b = 11.
С себя можно начать когда все остальное будет в порядке.  
Это сообщение редактировалось 06.07.2004 в 01:05

Rada

опытный

В самом деле, C++ смотрит по-разному на классы и встроенные типы.
С себя можно начать когда все остальное будет в порядке.  
+
-
edit
 

trainer

втянувшийся

Balancer:
Гм. Если i = ++i определено, то почему не определено i = (++i) + 1? :)
 
Между двуия sequence point значение скалярного объекта не может меняться более одного раза. Иначе - unspecified behavior.

По поводу того, что C++ устарел - вопросы внесения поправок в стандарт обсуждаются не менее двух раз в год, появляются соостветствующие сборники. Вполне возможно, что в ближайшие несколько лет может выйти новая редакция стандарта. :)

Balancer:
А скорость C# или даже Java сегодня практически на одном уровне с C++ даже на чисто вычислительных задачах, там, где проигрыш максимален
 
В Java и C# сейчас используются JIT-компиляторы, которые переводят соответствующий байт-код в машинный код процессора перед исполнением программы.
Во имя Ctrl, Alt и святаго Del. Enter!
 
+
-
edit
 

Balancer

администратор
★★★★★
trainer, 06.07.2004 10:39:31 :
Между двуия sequence point значение скалярного объекта не может меняться более одного раза. Иначе - unspecified behavior.
 


Кошмар какой! Говорю же - устарел язык :D

>В Java и C# сейчас используются JIT-компиляторы, которые переводят соответствующий байт-код в машинный код процессора перед исполнением программы.

Да оно как бы итак известно. Но это всё малоинтересные для массового программера детали. Для него интересно, что язык более высокого уровня, с привычным синтаксисом и идеологией, со сборкой мусора и т.п. практически не даёт проигрыша в скорости.

Учить Ocaml или Eiffel многим в лом, а вот переучиваться с C++ на Java, а, тем более, на C# нужно куда меньше :) А сделать можно больше. Сильно больше.
 
RU Филич #06.07.2004 10:55
+
-
edit
 

Филич

втянувшийся

Rada
ну здесь же не операторы, а просто функции
code text
  1. class Integer
  2. {
  3. public:
  4.     Integer(int Num) : m_iNum(Num) {}
  5.     operator int() { return m_iNum; }
  6.  
  7.     Integer operator+(const Integer& I) { return m_iNum + I.m_iNum; }
  8.     Integer operator++() { return m_iNum++; }
  9.     Integer& operator = (const Integer& I) { m_iNum = I.m_iNum; return *this; }
  10. private:
  11.     int m_iNum;
  12. };
  13.  
  14. int main(int argc, char* argv[])
  15. {
  16.     Integer a = 5;
  17.  
  18.     a = a++ + a++;
  19.  
  20.     return 0;
  21. }

code text
  1. Integer a = 5;
  2. 00412BEE  push        5    
  3. 00412BF0  lea         ecx,[a]
  4. 00412BF3  call        Integer::Integer (41150Ah)
  5.  
  6.     a = a++ + a++;
  7. 00412BF8  lea         eax,[ebp-0E0h]
  8. 00412BFE  push        eax  
  9. 00412BFF  lea         ecx,[a]
  10. 00412C02  call        Integer::operator++ (411500h)
  11. 00412C07  push        eax  
  12. 00412C08  lea         ecx,[ebp-0D4h]
  13. 00412C0E  push        ecx  
  14. 00412C0F  lea         edx,[ebp-0ECh]
  15. 00412C15  push        edx  
  16. 00412C16  lea         ecx,[a]
  17. 00412C19  call        Integer::operator++ (411500h)
  18. 00412C1E  mov         ecx,eax
  19. 00412C20  call        Integer::operator+ (411514h)
  20. 00412C25  push        eax  
  21. 00412C26  lea         eax,[ebp-0C8h]
  22. 00412C2C  push        eax  
  23. 00412C2D  lea         ecx,[a]
  24. 00412C30  call        Integer::operator= (41151Eh)
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

trainer

втянувшийся

Balancer:
Кошмар какой! Говорю же - устарел язык :D
 
Это не кошмар - это небольшая головоломка. :D Иначе жизнь станет неинтересной. :) Просто язык C++ позволяет делать то, что в реальной жизни использовать не стоит. :) Это как перегрузка операторов - можно перегрузить оператор + так, чтобы он выполнял вычитание.

Balancer:
Для него интересно, что язык более высокого уровня, с привычным синтаксисом и идеологией, со сборкой мусора и т.п. практически не даёт проигрыша в скорости.
 
JIT-компиляторы тоже неглупые люди пишут. :) Там в критических местах сборку мусора стараются не делать. Да и в C++ можно реализовать некое подобие сборки мусора - класс std::auto_ptr и аналогичные в сторонних библиотеках. :)
Во имя Ctrl, Alt и святаго Del. Enter!
 
+
-
edit
 

Balancer

администратор
★★★★★
trainer, 06.07.2004 11:03:21 :
Иначе жизнь станет неинтересной. :)
 


Не... У меня иные развлечения :)

>Просто язык C++ позволяет делать то, что в реальной жизни использовать не стоит. :)

Что в наше время является явным недостатком языка :)
На ассемблере тоже можно писать с продвинутыми макросами, объектами и т.п.
А MSIL - так и вовсе весь насквозь объектный :)

>Это как перегрузка операторов - можно перегрузить оператор + так, чтобы он выполнял вычитание.

Ну, не фортеру тебе про это рассказывать :)
мой старый прикол:
code text
  1. 3 3 * . -> 9
  2. 2 3 * . -> 6
  3. 4 1 * . -> 4
  4. 2 2 * . -> 5

:)
Там было переопределение слова умножения с прямой проверкой операндов на 2 и 2 :)

>JIT-компиляторы тоже неглупые люди пишут. :)

Естественно :)

>Там в критических местах сборку мусора стараются не делать.

Дык, правильно.

>Да и в C++ можно реализовать некое подобие сборки мусора - класс std::auto_ptr и аналогичные в сторонних библиотеках. :)

Речь же не о самой сборке мусора, а о возможностях, на это повязанных. Массивы с плавающими границами, массивы массивов, кольцевые присваивания объектов и т.д. и т.п. Есть масса задач, которые очень тяжело реализуются на Си++, восновном в области сложных структур данных - графы, там, их обработка.

Кстати, добрался я и до того, чтобы самому скомпилить свой фрагмент. VC++7, полная оптимизация:

code 6502acme
  1. ; 5    :     int a=5;
  2. ; 6    :     int b, c;
  3. ; 7    :     a=(b=(a++)) + (c=(a++));
  4. ; 8    :     printf("a=%d, b=%d, c=%d\n", a, b, c);
  5.  
  6.   00000 6a 05        push    5
  7.   00002 6a 05        push    5
  8.   00004 6a 0c        push    12         ; 0000000cH
  9.   00006 68 00 00 00 00   push    OFFSET FLAT:??_C@_0BC@FBPOBFPB@a?$DN?$CFd?0?5b?$DN?$CFd?0?5c?$DN?$CFd?6?$AA@
  10.   0000b e8 00 00 00 00   call    _printf
  11.   00010 83 c4 10     add     esp, 16            ; 00000010H
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 06.07.2004 10:55:42 :
code text
  1. Integer a = 5;
  2. 00412C02  call        Integer::operator++ (411500h)
  3. 00412C07  push        eax  
  4. 00412C08  lea         ecx,[ebp-0D4h]
  5. 00412C0E  push        ecx  
  6. 00412C0F  lea         edx,[ebp-0ECh]
  7. 00412C15  push        edx  
  8. 00412C16  lea         ecx,[a]
  9. 00412C19  call        Integer::operator++ (411500h)
 


При полной оптимизации - тоже всё ок :)

code 6502acme
  1. ; 18   :     Integer a = 5;
  2. ; 19   :
  3. ; 20   :     a = a++ + a++;
  4.  
  5.   00000 b8 0b 00 00 00   mov     eax, 11            ; 0000000bH


 
RU Филич #06.07.2004 12:34
+
-
edit
 

Филич

втянувшийся

Balancer
я тут прикинул. в принципе все верно, что a = a++ + a++; дает 12. "++" это постфиксный оператор, выполняться он будет после sequence point, то есть после ";" . так что верно компилер мыслит :). ты же написав for(int i = 100; i > 0; i--) не требуешь, что бы в цикле значение i было после выполнения "--".
а в случае с class Integer - сам понимаешь ни о каких операторах речи не идет.
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 06.07.2004 12:34:14 :
я тут прикинул. в принципе все верно, что a = a++ + a++; дает 12. "++" это постфиксный оператор, выполняться он будет после sequence point
 


Да, в этом смысле верно. Но тогда i = i++ не должно менять значение i, не так ли?

>ты же написав for(int i = 100; i > 0; i--) не требуешь, что бы в цикле значение i было после выполнения "--".

Нет. for(a;b;c) {d;}- это совсем другое. Это:
a;
while(b)
{ d; c;}

Т.е. инкремент выполняется всегда в конце цикла.

Если напишешь i=i-1 вместо i--; у тебя же в теле цикла не будет использоваться значение i на единицу меньшее :)
 
+
-
edit
 

Balancer

администратор
★★★★★
Balancer, 06.07.2004 12:43:38 :
Но тогда i = i++
 


Кстати, кто там писал про то, что в Си определено выражение i = i++?
Фиг там оно определено.

Если i++ выполняется до присваивания, то i будет равно исходному значению.
Если после - то результат будет на единицу больше, что не логично по определению оператора i++.

Так вот, на практике:
code cpp
  1. int main(void)
  2. {
  3.     int a=5;
  4.     a = a++;
  5.     printf("%d",a);
  6. }

выдаёт 6!

Т.е. инкремент срабатывает после присваивания.
Выходит противоречние.

А вот на PHP/C#/etc - всё верно! Результат равен 5.

В общем, i = i++; тоже недопустимая конструкция.
 
RU Филич #06.07.2004 12:50
+
-
edit
 

Филич

втянувшийся

Balancer
Да, в этом смысле верно. Но тогда i = i++ не должно менять значение i, не так ли?
 

почему? сначала же выполняется присваивание, а уж потом инкремент.

Если напишешь i=i-1 вместо i--; у тебя же в теле цикла не будет использоваться значение i на единицу меньшее
 

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

Balancer

администратор
★★★★★
Филич, 06.07.2004 12:50:17 :
почему? сначала же выполняется присваивание, а уж потом инкремент.
 


мне другое интересно, почему во всех Си-подобных языках, которые я перепробовал, этих неопределённостей нет и ++ работает так, как сказано в стандартных описаниях (берётся значение, после чего переменная увеличивается), а вот ни в одной реализации Си++ - нет. Типа, последователи дух и букву соблюдают лучше оригинала? :)
 
RU Филич #06.07.2004 12:57
+
-
edit
 

Филич

втянувшийся

а с чего ты решил, что постфиксная операция должна выполняться до конца выражения? имхо все верно :)
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 06.07.2004 12:57:21 :
а с чего ты решил, что постфиксная операция должна выполняться до конца выражения? имхо все верно :)
 


Да читал когда-то. М.б. даже у того же Кернигана с Ричи :D
Вообще, формально работу ++ описывают именно как взять старое значение и увеличить переменную. Ну и, хоть не указывается, но по логике-то (и по реализации ++ в других языках!) увеличивается тут же, а не после завершения всего вычисления.
 
+
-
edit
 

Balancer

администратор
★★★★★
Вот, из Кернигана-Ричи:
Эффект в обоих случаях состоит в увеличении N. Но выражение
++N увеличивает переменную N до использования ее значения, в
то время как N++ увеличивает переменную N после того, как ее
значение было использовано.
 


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

В первом случае мы получаем непоределённости. Во втором - строгую работу. Так что не удивительно, что в большинстве реализаций Си-синтаксиса выполняется именно эта нотация. Непонятно почему по-другому решили разработчики современных стандартов Си++.
 
RU Филич #06.07.2004 13:14
+
-
edit
 

Филич

втянувшийся

в то время как N++ увеличивает переменную N после того, как ее
значение было использовано.
 

тезка, но тут же так и написано, как и выполняет компилятор :)
сначала используем (присваиваем) а потом увеличиваем.
существуют только два типа кораблей: подводные лодки и их цели
 
RU Филич #06.07.2004 13:15
+
-
edit
 

Филич

втянувшийся

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

Balancer

администратор
★★★★★
Филич, 06.07.2004 13:14:42 :
сначала используем (присваиваем) а потом увеличиваем.
 


Это "потом" может читаться двояко.

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

Perl, PHP, C# ...
 
RU Филич #06.07.2004 13:23
+
-
edit
 

Филич

втянувшийся

Balancer
неа, "потом" это однозначно после sequence point :)
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 06.07.2004 13:23:09 :
неа, "потом" это однозначно после sequence point :)
 


Покажи мне, где это явно указано? Или хотя бы намёк на это? :)

Такого понятия-то у Кернигана и Ричи не было :D

И я всё равно требую продолжения банкета ответа - почему разработчики других языков считают иначе? :)
 
RU Филич #06.07.2004 13:43
+
-
edit
 

Филич

втянувшийся

вот тут.
http://www.kuzbass.ru:8086/docs/isocpp/expr.html#expr.comma
ну а почему в других языках считают иначе... считали бы так же, наверное писали бы на С/С++ и ничего нового не изобретали :)
существуют только два типа кораблей: подводные лодки и их цели
 
+
-
edit
 

Balancer

администратор
★★★★★
Филич, 06.07.2004 13:43:50 :
считали бы так же, наверное писали бы на С/С++ и ничего нового не изобретали :)
 


Да их, знаешь, не из-за несоответствия синтаксиса ++ пишут :D
 
+
-
edit
 

Balancer

администратор
★★★★★
А я всё об i = i++;

Всё же, по логике:
i++ возвращает старое значение i, так?
Это значение присваивается пременной i.

Так почему, скажите, т.е., по какой логике, i оказывается в итоге равным i+1? :)

Это противоречит любой нормальной логике :)
 
1 2 3 4 5 6

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