4 ms·
My first experience with UB: foo(bar(), bar()); (where bar() was stateful) Discovering that g++ and clang++ compiled to one that did what I wanted and on
by joatmon-snoo 10y ago
My first experience with UB:
foo(bar(), bar());
(where bar() was stateful)
Discovering that g++ and clang++ compiled to one that did what I wanted and one that didn't was an interesting experience.
- qb45 10y agoIt gets even funnier in OCaml where they nominally defined it UB in order to get the freedom to make the only existing implementation always 100% reliably evaluate right-to-left, which reportedly was better for performance or something :) And before somebody wonders about currying and eager evaluation, the problem is not functions but type constructors, which aren't curried.
- ufo 10y agoThe ocaml one is very annoying because the bytecode interpreter reliably evaluates arguments left-to-right but when you compile to native code it reliably evaluates right-to-left (or the other way around, I don't remember).
- deleted 10y ago[deleted]
- afrisch 10y agoI don't think so. Both bytecode and native evaluate right-to-left.
- ufo 10y agoI swear that I remember having programs that could behave differently in the bytecode and native compiler. Perhaps I'm remembering an older version of the compiler or another order-of-evaluation issue other than function parameters?
- gravypod 10y agoThe functions arguments are pushed onto the stack. From within the function you can think of the stack as an array. void test(a, b, c) stack[0] == a stack[1] == b stack[2] == c But to get the items in the stack in that order you have to... puch c push b push a If you wanted to do that, and still allow for left to right evaluation you could... temp_a = a temp_b = b temp_c = c push c puch b push a That would be 2x instructions for every (already expensive at that time) function call. Defining unordered evaluation as UB was to avoid having to do temp_a, temp_b, temp_c. Now compiles can do that and trivially optimize that sort of thing out.
- jacquesm 10y agoExcept that in most cases that's not how it is done. Instead, the stackframe is created in one go with a single change to the stack pointer and then the values are filled in in whatever order the compiler / language desires. Here is a typical example using GCC: movq %rsp, %rbp subq $16, %rsp movl $12, -4(%rbp) addl $1, -4(%rbp) movl -4(%rbp), %eax movl $14, %edx movl %eax, %esi movl $12, %edi call f Which moves the parameters using registers (subject to availability) as a further optimization. The 'subq' reserves space for the stackframe with addresses relative to rbp being the parameters.
- ot 10y agoThat's not UB. Argument evaluation order is unspecified, not undefined.
- wyldfire 10y agoHe meant unspecified behavior. ;)
- greglindahl 10y agoThe SGI compiler (now Open64) evaluates function arguments from right to left, unlike most other compilers. As a result we (PathScale) had to educate numerous users that the order is not guaranteed.
- kirab 10y agoStarting with C++17 evaluation order in this case (and most other cases) is finally specified and standardized! This is the accepted proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p014...