Непонятное поведение компилятора
От: SergeyT  
Дата: 10.10.07 07:16
Оценка: :)
Здравтсвуйте.

Возможно этот вопрос уже обсуждался, но я к сожалению поиском не нашел.

Результатом работы следующего кода является вывод:
2134, хотя на мой взгляд должно быть 1234, проверял на VC++ 8.0 и 7.1

int inc( )
{
  static int val = 0;
  return ++val;
}

int main(int argc, _TCHAR* argv[])
{
  cout << inc( ) << inc( );
  cout << inc( );
  cout << inc( );

  return 0;
}


Чем объяснить такое поведение компилятора?
Re: Непонятное поведение компилятора
От: AleksandrN Россия  
Дата: 10.10.07 07:35
Оценка: :)
Здравствуйте, SergeyT, Вы писали:

ST>Здравтсвуйте.


ST> Возможно этот вопрос уже обсуждался, но я к сожалению поиском не нашел.


ST>Результатом работы следующего кода является вывод:

ST>2134, хотя на мой взгляд должно быть 1234, проверял на VC++ 8.0 и 7.1

ST>
ST>int inc( )
ST>{
ST>  static int val = 0;
ST>  return ++val;
ST>}

ST>int main(int argc, _TCHAR* argv[])
ST>{
ST>  cout << inc( ) << inc( );
ST>  cout << inc( );
ST>  cout << inc( );

ST>  return 0;
ST>}
ST>


ST>Чем объяснить такое поведение компилятора?


Только что проверил, VC 6.0 выдаёт 2134, Intel C++ 8.1 выдаёт 1234, gcc (под Windows) — 2134

Интересно, какой компилятор глючит?
Re: Непонятное поведение компилятора
От: Sergey Россия  
Дата: 10.10.07 07:45
Оценка: -1 :)
"SergeyT" <11326@users.rsdn.ru> wrote in message news:2687726@news.rsdn.ru...

>
>  cout << inc( ) << inc( );
>

> Чем объяснить такое поведение компилятора?

Вычисляется сначала правый inc( ), потом левый. Обычное дело. Если нужен порядок вычислений, совпадающий с порядком вывода, возвращайте из своих функций временные объекты, которые будут делать инкремент непосредственно в операторе вывода. Типа такого:

 struct indent_t
 {
  struct incr
  {
   indent_t& src_;
   explicit incr(indent_t& src) : src_(src) {}
  };
  struct decr
  {
   indent_t& src_;
   explicit decr(indent_t& src) : src_(src) {}
  };
  int n_;
  explicit indent_t(int n = 1) : n_(n) {}
  incr operator++()
  { return incr(*this); }
  decr operator--()
  { return decr(*this); }
 };
 inline std::ostream& operator<<(std::ostream& os, indent_t v)
 {
  for (int n = v.n_; n != 0; --n)
   os << "  ";
  return os;
 }
 inline std::ostream& operator<<(std::ostream& os, indent_t::incr v)
 {
  ++v.src_.n_;
  return os << v.src_;
 }
 inline std::ostream& operator<<(std::ostream& os, indent_t::decr v)
 {
  --v.src_.n_;
  return os << v.src_;
 }


Использование:

indent_t indent;

output << ++indent << "чегонибудь" << endl

        << ++indent << "еще чегонибудь" << endl;
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: Непонятное поведение компилятора
От: AleksandrN Россия  
Дата: 10.10.07 07:45
Оценка: -1
Здравствуйте, AleksandrN, Вы писали:

AN>Здравствуйте, SergeyT, Вы писали:


ST>>Здравтсвуйте.


ST>> Возможно этот вопрос уже обсуждался, но я к сожалению поиском не нашел.


ST>>Результатом работы следующего кода является вывод:

ST>>2134, хотя на мой взгляд должно быть 1234, проверял на VC++ 8.0 и 7.1

ST>>
ST>>int inc( )
ST>>{
ST>>  static int val = 0;
ST>>  return ++val;
ST>>}

ST>>int main(int argc, _TCHAR* argv[])
ST>>{
ST>>  cout << inc( ) << inc( );
ST>>  cout << inc( );
ST>>  cout << inc( );

ST>>  return 0;
ST>>}
ST>>


ST>>Чем объяснить такое поведение компилятора?


AN>Только что проверил, VC 6.0 выдаёт 2134, Intel C++ 8.1 выдаёт 1234, gcc (под Windows) — 2134


AN>Интересно, какой компилятор глючит?


Понял
Вот ассемблерный код, сгенерированный VC++:

    TITLE    1.cpp
    .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
_DATA    SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA    ENDS
CONST    SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST    ENDS
_BSS    SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS    ENDS
_TLS    SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS    ENDS
;    COMDAT ?lock@ios@@QAAXXZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?unlock@ios@@QAAXXZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?unlockbuf@ios@@QAAXXZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?gptr@streambuf@@IBEPADXZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?setf@ios@@QAEJJJ@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?rdbuf@ios@@QBEPAVstreambuf@@XZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ??4istream@@IAEAAV0@ABV0@@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ??6ostream@@QAEAAV0@P6AAAV0@AAV0@@Z@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ??6ostream@@QAEAAV0@D@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?flush@@YAAAVostream@@AAV1@@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ??4iostream@@IAEAAV0@PAVstreambuf@@@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
FLAT    GROUP _DATA, CONST, _BSS
    ASSUME    CS: FLAT, DS: FLAT, SS: FLAT
endif
_BSS    SEGMENT
_?val@?1??inc@@YAHXZ@4HA DD 01H DUP (?)
_BSS    ENDS
PUBLIC    ?inc@@YAHXZ                    ; inc
_TEXT    SEGMENT
?inc@@YAHXZ PROC NEAR                    ; inc
; File 1.cpp
; Line 5
    push    ebp
    mov    ebp, esp
; Line 7
    mov    eax, DWORD PTR _?val@?1??inc@@YAHXZ@4HA
    add    eax, 1
    mov    DWORD PTR _?val@?1??inc@@YAHXZ@4HA, eax
    mov    eax, DWORD PTR _?val@?1??inc@@YAHXZ@4HA
; Line 8
    pop    ebp
    ret    0
?inc@@YAHXZ ENDP                    ; inc
_TEXT    ENDS
PUBLIC    _main
EXTRN    ??6ostream@@QAEAAV0@H@Z:NEAR            ; ostream::operator<<
EXTRN    ?cout@@3Vostream_withassign@@A:BYTE        ; cout
_TEXT    SEGMENT
_main    PROC NEAR
; Line 11
    push    ebp
    mov    ebp, esp
; Line 12
    call    ?inc@@YAHXZ                ; inc
    push    eax
    call    ?inc@@YAHXZ                ; inc
    push    eax
    mov    ecx, OFFSET FLAT:?cout@@3Vostream_withassign@@A
    call    ??6ostream@@QAEAAV0@H@Z            ; ostream::operator<<
    mov    ecx, eax
    call    ??6ostream@@QAEAAV0@H@Z            ; ostream::operator<<
; Line 13
    call    ?inc@@YAHXZ                ; inc
    push    eax
    mov    ecx, OFFSET FLAT:?cout@@3Vostream_withassign@@A
    call    ??6ostream@@QAEAAV0@H@Z            ; ostream::operator<<
; Line 14
    call    ?inc@@YAHXZ                ; inc
    push    eax
    mov    ecx, OFFSET FLAT:?cout@@3Vostream_withassign@@A
    call    ??6ostream@@QAEAAV0@H@Z            ; ostream::operator<<
; Line 16
    xor    eax, eax
; Line 17
    pop    ebp
    ret    0
_main    ENDP
_TEXT    ENDS
END

т.е. сперва два раза подряд вызываются функция inc() и результаты заталкиваются в стек, затем они берутся из стека и передаются cout::operator<<.


А вот, что генерирует интеловский компилятор:
; -- Machine type IA32
; mark_description "Intel(R) C++ Compiler for 32-bit applications, Version 8.1    Build 20050628Z %s";
; mark_description "-Qvc6 -Qlocation,link,C:\\Program Files\\Microsoft Visual Studio\\VC98\\Bin -Fa1i.asm";
;ident "Intel(R) C++ Compiler for 32-bit applications, Version 8.1    Build 20050628Z %s"
;ident "-Qvc6 -Qlocation,link,C:\\Program Files\\Microsoft Visual Studio\\VC98\\Bin -Fa1i.asm"
    .486P
     .387
    OPTION DOTNAME
_TEXT    SEGMENT DWORD PUBLIC FLAT 'CODE'
    ALIGN 004H
_TEXT    ENDS
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
    ALIGN 004H
_DATA    ENDS
_BSS    SEGMENT DWORD PUBLIC FLAT 'BSS'
    ALIGN 004H
_BSS    ENDS
_RDATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
    ALIGN 004H
_RDATA    ENDS
_TEXT1    SEGMENT DWORD PUBLIC FLAT 'CODE'
    ALIGN 004H
_TEXT1    ENDS
_DATA1    SEGMENT DWORD PUBLIC FLAT 'DATA'
    ALIGN 004H
_DATA1    ENDS
    ASSUME    CS:FLAT,DS:FLAT,SS:FLAT
;ident "-defaultlib:libci"
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA    ENDS
_TEXT    SEGMENT DWORD PUBLIC FLAT 'CODE'
;    COMDAT ?inc@@YAHXZ
; -- Begin  ?inc@@YAHXZ
; mark_begin;
IF @Version GE 612
  .MMX
  MMWORD TEXTEQU <QWORD>
ENDIF
IF @Version GE 614
  .XMM
  XMMWORD TEXTEQU <OWORD>
ENDIF
       ALIGN     4
    PUBLIC ?inc@@YAHXZ

?inc@@YAHXZ    PROC NEAR
$B1$1:                          ; Preds $B1$0
        mov       eax, DWORD PTR val$327                        ;7.12
        add       eax, 1                                        ;7.12
        mov       DWORD PTR val$327, eax                        ;7.12
        ret                                                     ;7.12
        ALIGN     4
                                ; LOE
; mark_end;
?inc@@YAHXZ ENDP
;?inc@@YAHXZ    ENDS
_TEXT    ENDS
_BSS    SEGMENT DWORD PUBLIC FLAT 'BSS'
val$327    DD 1 DUP (?)    ; pad
_BSS    ENDS
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA    ENDS
; -- End  ?inc@@YAHXZ
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA    ENDS
_TEXT    SEGMENT DWORD PUBLIC FLAT 'CODE'
;    COMDAT _main
; -- Begin  _main
; mark_begin;
       ALIGN     4
    PUBLIC _main

_main    PROC NEAR
; parameter 1: 8 + ebp
; parameter 2: 12 + ebp
$B2$1:                          ; Preds $B2$0
        push      ebp                                           ;11.1
        mov       ebp, esp                                      ;11.1
        sub       esp, 3                                        ;11.1
        and       esp, -8                                       ;11.1
        add       esp, 4                                        ;11.1
        push      ebx                                           ;11.1
        push      esi                                           ;11.1
        call      ___intel_proc_init                            ;11.1
        call      ?inc@@YAHXZ                                   ;12.11
                                ; LOE eax esi edi
$B2$2:                          ; Preds $B2$1
        push      eax                                           ;12.11
        mov       ecx, OFFSET FLAT: ?cout@@3Vostream_withassign@@A ;12.8
        call      ??6ostream@@QAEAAV0@H@Z                       ;12.8
                                ; LOE eax esi edi
$B2$13:                         ; Preds $B2$2
        mov       ebx, eax                                      ;12.8
                                ; LOE ebx esi edi
$B2$3:                          ; Preds $B2$13
        call      ?inc@@YAHXZ                                   ;12.21
                                ; LOE eax ebx esi edi
$B2$4:                          ; Preds $B2$3
        push      eax                                           ;12.21
        mov       ecx, ebx                                      ;12.18
        call      ??6ostream@@QAEAAV0@H@Z                       ;12.18
                                ; LOE esi edi
$B2$5:                          ; Preds $B2$4
        call      ?inc@@YAHXZ                                   ;13.11
                                ; LOE eax esi edi
$B2$6:                          ; Preds $B2$5
        push      eax                                           ;13.11
        mov       ecx, OFFSET FLAT: ?cout@@3Vostream_withassign@@A ;13.8
        call      ??6ostream@@QAEAAV0@H@Z                       ;13.8
                                ; LOE esi edi
$B2$7:                          ; Preds $B2$6
        call      ?inc@@YAHXZ                                   ;14.11
                                ; LOE eax esi edi
$B2$8:                          ; Preds $B2$7
        push      eax                                           ;14.11
        mov       ecx, OFFSET FLAT: ?cout@@3Vostream_withassign@@A ;14.8
        call      ??6ostream@@QAEAAV0@H@Z                       ;14.8
                                ; LOE esi edi
$B2$9:                          ; Preds $B2$8
        xor       eax, eax                                      ;16.10
        pop       ecx                                           ;16.10
        pop       ebx                                           ;16.10
        mov       esp, ebp                                      ;16.10
        pop       ebp                                           ;16.10
        ret                                                     ;16.10
        ALIGN     4
                                ; LOE
; mark_end;
_main ENDP
;_main    ENDS
_TEXT    ENDS
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA    ENDS
; -- End  _main
_DATA    SEGMENT DWORD PUBLIC FLAT 'DATA'
EXTRN    ?cout@@3Vostream_withassign@@A:BYTE
EXTRN    ?cout@@3Vostream_withassign@@A:BYTE
_DATA    ENDS
EXTRN    ??6ostream@@QAEAAV0@H@Z:PROC
EXTRN    ___intel_proc_init:PROC
    END

ИМХО, поведение Intel C++ — правильное.
Re[3]: Непонятное поведение компилятора
От: Sergey Россия  
Дата: 10.10.07 07:47
Оценка:
> ИМХО, поведение Intel C++ — правильное.

У обоих поведение правильное. Никто не обещал, что вычислятся все будет в том порядке, в каком вы ожидаете.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Непонятное поведение компилятора
От: Erop Россия  
Дата: 10.10.07 07:48
Оценка: 1 (1) +2
Здравствуйте, SergeyT, Вы писали:

ST>
ST>int main(int argc, _TCHAR* argv[])
ST>{
ST>  cout << inc( ) << inc( );
ST>  cout << inc( );
ST>  cout << inc( );

ST>  return 0;
ST>}
ST>


ST>Чем объяснить такое поведение компилятора?

Тем, что порядок вычисления аргументов функций не определён...
твоё выражение cout << inc() << inc() можно переписать так:
operator << ( operator << ( count, inc() ), inc() )

Это немного не корректно, но более точное разбирательство нас только запутает.
Ну так вот, компилятор может вычислить аргументы обеих operator << в любом порядке
Например он может вычислять все аргументы слева направо.
Тогда он сначала вычислит operator( count, inc() ), а потом вычислит второй inc(), в результате чего выведется 12, а может вычислять справа налево, тогда он сначала вычислить второй inc(), потом operator( count, inc() ), в результате чего выведет 21...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вот так "мегакодеры" и возникают...
От: Erop Россия  
Дата: 10.10.07 08:00
Оценка:
Здравствуйте, Sergey!

Люди совершенно базовых вещей не понимают, а ты им таких крокодилов рекоммендуешь ((

Есть ведь намного более простое и понятное решение, например такое:
const int toOut1 = inc();
const int toOut2 = inc();
std::cout << toOut1 << toOut2;
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Непонятное поведение компилятора
От: remark Россия http://www.1024cores.net/
Дата: 10.10.07 08:41
Оценка:
Здравствуйте, SergeyT, Вы писали:

ST>Чем объяснить такое поведение компилятора?


А чем объяснить рассуждения людей, которые считают, что должно выводится 1234?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Непонятное поведение компилятора
От: AleksandrN Россия  
Дата: 10.10.07 09:08
Оценка:
Здравствуйте, Sergey, Вы писали:

>> ИМХО, поведение Intel C++ — правильное.


S>У обоих поведение правильное. Никто не обещал, что вычислятся все будет в том порядке, в каком вы ожидаете.


Да, поглядел в стандарт — определён только порядок вычисления выражения (с некоторыми исключениями), а порядок вычисления операндов выражения не определён.
Re[2]: Непонятное поведение компилятора
От: Кодт Россия  
Дата: 10.10.07 09:23
Оценка:
Здравствуйте, Erop, Вы писали:

ST>>Чем объяснить такое поведение компилятора?

E>Тем, что порядок вычисления аргументов функций не определён...
... что в данном случае ведёт к unspecified behavior
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.