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?
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+, butc()
may be evaluated first, last, or betweena()
orb()
at run time.