Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > не понимаю компилятор


Автор: 17dufa 30.10.2009, 11:47
Добрый день. Есть красивая подстава на собеседовании: int i = 0; i = i++; чему равно i?
однако, компилятор мелкософта, а по сведениям и какие-то из линуксовых выдают i == 1.
вот собственно код
Код

class ii
{
    int val;
public:
    ii(int j) : val(j){}
    ii & operator = (ii&op)
    {
        this->val = op.val;
        return *this;
    }
    ii operator++(int)
    {
        ii buf = *this;
        this->val++;
        return buf;
    }
};

int main()
{
    int jk = 0;
    jk = jk++;
    ii i = 0;
    i = i++;
    int j = 0;
}

при выходе из main jk = 1, а вот i.val = 0 - как и ожидалось. откуда такая разница для встроенного и пользовательского типа?

Автор: Alek86 30.10.2009, 12:04
оттуда, что поведение не определено (или не специфицированно, не помню точно)
если ты напишешь код, у которого undefined behaviour, компилятор имеет моральное право хоть код для BSOD'а вставлять smile

Автор: mes 30.10.2009, 12:22
для удобства в выражении i = i++; заменим i ссылками на нее же :    
Код

int & i1 = i;
int & i2 = i;  
i2 = i1++;


теперь разобьем по действиям :
(условно a и b регистры процессора)
Код

a = i1;
b = a + 1;

// i1 = b; 
i2 = a;    // i = 1;
// i1 = b; // i = 0;

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

Автор: 17dufa 30.10.2009, 12:57
Alek86, что конкретно в этом коде выводит нас в чудную область undefined behaviour?


mes, думаю Вы несколько ошиблись в коде (перепутали a и b в последней части)
Код

a = i1;
b = a + 1;
// i1 = b; 
i2 = a;    // i = 1;
// i1 = b; // i = 0;

а разве не определено стандартом, что сначала вычисляется правое выражение, а затем уже выполняется оператор равенства?
это ж форменный бардак получается, если side эффекты правого выражения вычисляются после выполнения равенства.

Автор: mes 30.10.2009, 13:21
Цитата(17dufa @  30.10.2009,  11:57 Найти цитируемый пост)
думаю Вы несколько ошиблись в коде 

спасибо.. подправил..

Цитата(17dufa @  30.10.2009,  11:57 Найти цитируемый пост)
а разве не определено стандартом, что сначала вычисляется правое выражение, а затем уже выполняется оператор равенства?

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

Добавлено через 6 минут и 6 секунд
Цитата(17dufa @  30.10.2009,  11:57 Найти цитируемый пост)
это ж форменный бардак получается

Стандарт Вас честно предупреждает о возможности side-эффекта, и это уж на совести программиста создвать бардак или нет 
 smile 

Автор: tilin 30.10.2009, 13:30
Цитата(17dufa @  30.10.2009,  11:47 Найти цитируемый пост)
Есть красивая подстава на собеседовании: int i = 0; i = i++; чему равно i?
однако, компилятор мелкософта, а по сведениям и какие-то из линуксовых выдают i == 1.


А почему i не должно быть равно 1? i хранится в памяти. i инкрементируется и сохраняется опять же туда. Соответственно при чтении i читается из памяти и читается именно 1. Асм код от мелкософта:
Код

    int i = 0; 
004114AE  mov         dword ptr [i],0 
    i = i++;
// i = i
004114B5  mov         eax,dword ptr [i] 
004114B8  mov         dword ptr [i],eax

// i++ 
004114BB  mov         ecx,dword ptr [i] 
004114BE  add         ecx,1 
004114C1  mov         dword ptr [i],ecx

Автор: mes 30.10.2009, 13:32
Цитата(tilin @  30.10.2009,  12:30 Найти цитируемый пост)
А почему i не должно быть равно 1? 

потому что может быть и другая реализация..

Цитата(tilin @  30.10.2009,  12:30 Найти цитируемый пост)
Асм код от мелкософта:

Не мелкософтом единным жив программист smile

Автор: tilin 30.10.2009, 13:35
А при другой реализации i будет храниться в двух разных местах что-ли? Ведь, если хранится в одном месте памяти, то i++ изменяет значение именно этой ячейки и соответственно  i == 1 при любом порядке выполнения.

Автор: 17dufa 30.10.2009, 13:40
tilin, ну вот Вы и попалисьsmile
i=i++ - это единая конструкция. и в оператор = передается значение i до инкрементирования, то есть 0. потом происходит инкремент, i становится 1, потом собственно выполняется оператор = и i снова становится 0;) а приведенный Вами код несколько отличается от того, что я написал в самом начале. так что в идеале i = 0. что и происходит с моим типом ii. там компилятор себе такого не позволяет.


mes, ну все, если терь меня такое спросят так и буду грить - undefined behaviour и Вашу красивую схему с регистрами smile главное чтоб работодатель с юмором попался, а то еще обидется.

tilin, исправились, так что и я исправлюсь - постфиксный инкремент создает копию объекта, глубоко по идее. так что да, в 2 местах будет хранится. обратите внимание на реализацию operator++(int) в первом посте темы.

Автор: mes 30.10.2009, 13:45
Цитата(tilin @  30.10.2009,  12:35 Найти цитируемый пост)
А при другой реализации i будет храниться в двух разных местах что-ли? Ведь, если хранится в одном месте памяти, то i++ изменяет значение именно этой ячейки и соответственно  i == 1 при любом порядке выполнения. 

 
если http://forum.vingrad.ru/index.php?showtopic=278366&view=findpost&p=2008829 остался без внимания, то повторю его изменив "Ваш" asm код :

Код

  mov         eax,dword ptr [i] 
  mov         ecx,dword ptr [i] 
  add         ecx,1 
  mov         dword ptr [i],ecx
  mov         dword ptr [i],eax

 smile

Добавлено через 6 минут
Цитата(17dufa @  30.10.2009,  12:40 Найти цитируемый пост)
главное чтоб работодатель с юмором попался, а то еще обидется.

позвольте узнать, на что он может обидеться ?!

Автор: Earnest 30.10.2009, 13:55
Цитата(17dufa @  30.10.2009,  14:40 Найти цитируемый пост)
i=i++ - это единая конструкция. и в оператор = передается значение i до инкрементирования, то есть 0. потом происходит инкремент

Нет, компилятор имеет право делать присваивание и инкремент в любом порядке, т.к. инкремент постфиксный. Порядок вычисления независимых подвыражений в statement не определен. А результат i++ (т.е. старое значение i) может храниться во временной переменной.

Автор: 17dufa 30.10.2009, 14:04
mes, если предположить, что он умный ровно настолько насколько я был до этого утра и твердо уверен что результат 0, то может обидеться, что я оказался умнее smile 

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

Автор: mes 30.10.2009, 14:06
Цитата(17dufa @  30.10.2009,  12:40 Найти цитируемый пост)
если терь меня такое спросят так и буду грить .. 

или  про точки следования, вот с википедии :
http://en.wikipedia.org/wiki/Sequence_point
 smile

Цитата(17dufa @  30.10.2009,  13:04 Найти цитируемый пост)
если предположить, что он умный ровно настолько насколько я был до этого утра и твердо уверен что результат 0, то может обидеться, что я оказался умнее smile 

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

Цитата(17dufa @  30.10.2009,  13:04 Найти цитируемый пост)
 вот где собака порылась. 

Все зависит от оптимизационных способностей компилятора..

Автор: 17dufa 30.10.2009, 14:16
mes, познавательно. и что самое интересное "i=i++;" даже обсуждается отдельно. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)