Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order of execution is different in different compilers [duplicate]

This code gives different outputs in XCode and in Visual Studio:

#include <iostream>

using namespace std;

int f() {
    cout << 'A';
    return 1;
}

int main() {
    cout << '.' << f();
    return 0;
}

In Visual Studio it outputs

A.1

In XCode it outputs

.A1

Obviously I'd expect both compilers to output the same thing.. Is it to be expected to not do that? Is it a known thing or is there anything I could do about this?

like image 233
Strasse34 Avatar asked Oct 22 '25 21:10

Strasse34


1 Answers

MSVC compiles the code differently than GCC apparently.

Inspecting the assembly code through Godbolt (using x86-64 gcc 13.2 and x64 msvc v19.38) shows that MSVC produces the following assembly for the main function:

tv69 = 32
main    PROC
$LN3:
        sub     rsp, 56                             ; 00000038H
        call    int f(void)                         ; f
        mov     DWORD PTR tv69[rsp], eax
        mov     dl, 46                                    ; 0000002eH
        lea     rcx, OFFSET FLAT:std::basic_ostream<char,std::char_traits<char> > std::cout ; std::cout
        call    std::basic_ostream<char,std::char_traits<char> > & std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > &,char) ; std::operator<<<std::char_traits<char> >
        mov     ecx, DWORD PTR tv69[rsp]
        mov     edx, ecx
        mov     rcx, rax
        call    std::basic_ostream<char,std::char_traits<char> > & std::basic_ostream<char,std::char_traits<char> >::operator<<(int) ; std::basic_ostream<char,std::char_traits<char> >::operator<<
        xor     eax, eax
        add     rsp, 56                             ; 00000038H
        ret     0
main    ENDP

... while GCC produces this:

main:
        push    rbp
        mov     rbp, rsp
        push    rbx
        sub     rsp, 8
        mov     esi, 46
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char)
        mov     rbx, rax
        call    f()
        mov     esi, eax
        mov     rdi, rbx
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        mov     rbx, QWORD PTR [rbp-8]
        leave
        ret

In the MSVC output, f() is called before the first operator<<, while GCC calls f() after calling the first operator<< on std::cout.

The reason for this is that in C++, the order of evaluation is unspecified:

Order of evaluation of any part of any expression, including order of evaluation of function arguments is unspecified (with some exceptions listed below). The compiler can evaluate operands and other subexpressions in any order, and may choose another order when the same expression is evaluated again.

There is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression a() + b() + c() is parsed as (a() + b()) + c() due to left-to-right associativity of operator+, but c() may be evaluated first, last, or between a() or b() at run time.

like image 160
kwyntes Avatar answered Oct 25 '25 11:10

kwyntes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!