0

Here's a little piece of code removed from an experiment with virtual machines. It's supposed to push and pop doubles from a byte buffer. However, it displays some very interesting behavior... specifically, it somehow makes printf print its arguments in reverse order, at least when compiled with MinGW g++ 4.8.1. What's going on? O_o

#include <stdio.h>

#define STACK_BYTES (1024 * 1024 * 2)

struct VM {
    uint8_t* stack;
    uint8_t* sp;

    VM()
    {
        stack = new uint8_t[STACK_BYTES];
        sp = stack;
    }

    ~VM()
    {
        delete[] stack;
    }

    void pushv(double val)
    {
        *(double*)sp = val;
        sp += sizeof(double);
    }

    double popv()
    {
        sp -= sizeof(double);
        return *(double*)sp;
    }
};

int main()
{   
    VM vm;

    vm.pushv(666.f);
    vm.pushv(777.f);
    vm.pushv(888.f);

    printf("%f ", vm.popv());
    printf("%f ", vm.popv());
    printf("%f\n", vm.popv()); // 888.000 777.000 666.000, as expected.

    printf("SP: %d\n", (int)(vm.sp - vm.stack)); // SP: 0, as expected.

    vm.pushv(666.f);
    vm.pushv(777.f);
    vm.pushv(888.f);

    printf("%f %f %f\n", vm.popv(), vm.popv(), vm.popv()); // 666.000 777.000 888.000???

    return 0;
}
nvoigt
  • 75,013
  • 26
  • 93
  • 142
user3026691
  • 497
  • 2
  • 11

2 Answers2

1

The standard didn't specify any order to evaluate parameters. You're code is unspecified:

printf("%f %f %f\n", vm.popv(), vm.popv(), vm.popv());

May has different result in various compiler implementation. You're first version is better.

masoud
  • 55,379
  • 16
  • 141
  • 208
0

The compiler evaluates the parameters to pass to the printf function from the last one, pushing them on the stack one after another from the last.
If the order is a problem, use intermediate variables.

Nicolas Defranoux
  • 2,646
  • 1
  • 10
  • 13
  • I think it's wrong _"from the last one ... "_. Standard doesn't say such a thing. – masoud May 10 '14 at 14:18
  • It's compiler dependent, but obviously in this case his compiler is doing it from the last one. – Nicolas Defranoux May 10 '14 at 14:20
  • I understand now. Function argument evaluation order can't be relied on. Does the same apply to the operands of the binary operators, like +? – user3026691 May 10 '14 at 14:21
  • I think so, + is just a function call after all. Though the order is defined for conditions (&&, ||) so that it's safe to use if (x != null && x->something()). – Nicolas Defranoux May 10 '14 at 14:24