Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ++i + ++i = 14, почему??? 
V
    Опции темы
kurtis
Дата 13.1.2008, 01:35 (ссылка)  | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 10.8.2007

Репутация: нет
Всего: нет



ну собсно вопрос возник из-за этой цитаты с бора http://bash.org.ru/quote/212679

Я совсем не понимаю как работает префиксный инкремент!!!=((
Код

int i = 5;
i = ++i + ++i;

т.е. сначало делаем первый прединкример, и получаем значение И равное 6, а потом инкрементируем значение И еще на единицу, и по идее у нас должно получиться выражение 6+7=13, но получается что-то вроде 7+7. Ну ладно, тут я еще логику работы компилятора понять могу, т.е. суммируются все-таки значения переменной И, а в конце строки значение переменной И равно 7, но как-то это странно.....

но если написать 
Код

int i = 5;
i = ++i + ++i + ++i;

то моя теория полностью рушится, т.к значение вместо ожидаемых 6+7+8=21 либо 8+8+8=24, мы получаем значение равное 22, а это на 1 больше чем в выражении 6+7+8=21!!!

Код

int i = 5;
i = ++i + ++i + ++i + ++i;

и тут понятное дело много всего непонятного, мы получаем 31, что тоже на 1 больше чем выражение 6+7+8+9=30 !!!
Что странно, мы всегда получаем значение на 1 больше чем по идее должны были.

Результат работы программы  
Код

++i + ++i =14
++i + ++i + ++i =22
++i + ++i + ++i + ++i =31

Terminated with return code 0
Press any key to continue ...


С умножением тоже как-то все не очень понятно
Код

++i * ++i =49
++i * ++i * ++i =392
++i * ++i * ++i *+ ++i =3528

Terminated with return code 0
Press any key to continue ...


т.е. тут уже четко видно как эти числа получены:
1) 7 * 7 = 49
2) 7 * 7 * 8 = 392
3) 7 * 7 * 8 * 9 = 3528

По идее на месте первой "семерки" должна быть "шестерка", а ее нету!!!
Собсно вопрос, что я неправильно делаю???
Спасибо за внимание!!!=))))

Код

#include <iostream>
using namespace std;

int main()
{
    int i = 5;
    i = ++i + ++i;
    cout << "++i + ++i =" <<i << endl;
    
    i = 5;
    i = ++i + ++i + ++i;
    cout << "++i + ++i + ++i =" << i << endl;

    i = 5;
    i = ++i + ++i + ++i + ++i;
    cout << "++i + ++i + ++i + ++i =" << i << endl;

    return 0;
}
Код





PM MAIL   Вверх
Daevaorn
Дата 13.1.2008, 01:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: нет
Всего: 70



Цитата(kurtis @  13.1.2008,  02:35 Найти цитируемый пост)
Собсно вопрос, что я неправильно делаю???

Пытаешься анализировать то, что анализироват не нужно. Это UB. Результат может быть любой.
PM MAIL WWW   Вверх
qweqwe
Дата 13.1.2008, 01:41 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 55
Регистрация: 31.1.2007

Репутация: нет
Всего: 0



сначала вычисляются аргументы ф-ии, а потом сама ф-я
в данном случае, сначала вычисляется ++i, потом ++i
а потом i+i , а i в этот момент = 7
PM MAIL   Вверх
Daevaorn
Дата 13.1.2008, 01:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: нет
Всего: 70



PM MAIL WWW   Вверх
kurtis
Дата 13.1.2008, 01:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 10.8.2007

Репутация: нет
Всего: нет



Цитата(qweqwe @ 13.1.2008,  01:41)
сначала вычисляются аргументы ф-ии, а потом сама ф-я
в данном случае, сначала вычисляется ++i, потом ++i
а потом i+i , а i в этот момент = 7

оно как бы да, но как бы нет, т.е. оно сначало вычислило ++и, потом ++и и потом ++и, а потом и+и+и, а и нас на тот момент было 8, т.е. в результате должно получится 24, а 24 не получается, получается 22

Добавлено через 14 минут и 19 секунд
ДА!
прошу прощения, действительно имеет место быть т.н. UB
Попробовал другой компилятор, выдало


Код

C:\Borland\BCC55\Bin>my
++i + ++i =49
++i + ++i + ++i =512
++i + ++i + ++i + ++i =6561





PM MAIL   Вверх
Zaff
Дата 13.1.2008, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 13.1.2008

Репутация: нет
Всего: нет



Конечно все зависит от конкретного кодогенератора. Например, в MSVC++6 конструкция int i = 5; i = ++i + ++i; будет преоброзована в следующий код:

Код

    mov    DWORD PTR _i$[ebp], 5 ; сначала присваиваем i=5

    mov    eax, DWORD PTR _i$[ebp] ; значение i в регистр eax
    add    eax, 1 ; инкрементируем eax на единицу
    mov    DWORD PTR _i$[ebp], eax ; и возвращаем обратно
    mov    ecx, DWORD PTR _i$[ebp] ; значение i в регистр ecx
    add    ecx, 1 ; инкрементируем ecx на единицу
    mov    DWORD PTR _i$[ebp], ecx ; и возвращаем обратно 
    mov    edx, DWORD PTR _i$[ebp] ; теперь перемещаем значение переменной i в регистр edx
    add    edx, DWORD PTR _i$[ebp] ; и складываем полученное с i :)
    mov    DWORD PTR _i$[ebp], edx ; теперь обратно все возвращаем в i


таким образом, мы получаем такую последовательность действий:
i = (i + 1 + 1);
i = i + i;

Теперь подумаем, почему так? Все просто - вспоминаем про приоритеты операций:
  • + (u)
  • - (u)
  • ++
  • -- (сначала инкремент)
  • *
  • /
  • %
  • + (b) (а теперь сложение)
  • - (b)
Таким образом, мы понимаем, что полученная конструкция получается правильной трансляцией языка Си в машинный язык.

Конструкция int i = 5; i = ++i + ++i + ++i; разворачивается в нижеследующую:

Код

    ; i = 5
    mov    DWORD PTR _i$[ebp], 5

    ; i = i + 1
    mov    eax, DWORD PTR _i$[ebp] 
    add    eax, 1
    mov    DWORD PTR _i$[ebp], eax i+1

    ; i = i + 1
    mov    ecx, DWORD PTR _i$[ebp]
    add    ecx, 1
    mov    DWORD PTR _i$[ebp], ecx i+1
    
    ; (самый важный момент!)
    ; edx = i + i
    mov    edx, DWORD PTR _i$[ebp]
    add    edx, DWORD PTR _i$[ebp]

    ; i = i + 1
    mov    eax, DWORD PTR _i$[ebp]
    add    eax, 1
    mov    DWORD PTR _i$[ebp], eax

    ; i =edx + i
    add    edx, DWORD PTR _i$[ebp]
    mov    DWORD PTR _i$[ebp], edx


То есть, сначала складываются первые два инкремента, а затем происходит третья инкрементация и сложение с результатом. Следуя математической логике, помня о приоритетах операций, принятых в СИ, данное решение правильно, так же, как i = 5; i = i + i + i * i; (i = 35).

Другие примеры работают по такой же логике. Замечено, что компилятор MSVC++ наиболее правильно работает с математикой.

PM MAIL   Вверх
Daevaorn
Дата 13.1.2008, 17:27 (ссылка) |    (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: нет
Всего: 70



Толку то? Результат всё равно не предсказуем. Закладываться на какое-то конкретное поведение компилятора глупо. Выход - не писать такие конструкции.
PM MAIL WWW   Вверх
Zaff
Дата 13.1.2008, 22:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 13.1.2008

Репутация: нет
Всего: нет



Daevaorn, ну вопрос звучал почему. Конечно, в реальных программах стоит использовать другие конструкции. В общем, как я говорю своим студентам - читаем С.Макконнела и проникаемся, проникаемся... smile

Это сообщение отредактировал(а) Zaff - 13.1.2008, 22:27
PM MAIL   Вверх
archimed7592
Дата 14.1.2008, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 6
Всего: 93



Zaff, надеюсь Вы сообщаете своим студентам о существовании Стандарта?

Добавлено через 1 минуту и 27 секунд
Цитата(Zaff @  13.1.2008,  22:25 Найти цитируемый пост)
Конечно, в реальных программах стоит использовать другие конструкции.

Не то что бы "стоит" - такие конструкции использовать вообще нельзя. Эти конструкции - ошибки, которые компилятор не в состоянии отследить на этапе компиляции.


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0624 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.