2

First of all here's the code :

//functions
char dernier(char* s){
    return s[strlen(s)-1];
}

char* debut(char* s){
    s[strlen(s)-1] = '\0';
    return s;
}

//problematic bit :
printf("%s %s %c", debut(s), s, dernier(s)); //s = "test"

I have expected the output to be tes tes s but I am getting tes tes t which I find odd.

Any idea why? Thank you!

GDGDJKJ
  • 209
  • 1
  • 7
  • 2
    Why is that odd? Obviously `dernier()` is called first. – Weather Vane Jan 28 '19 at 19:31
  • yes so the new string is "tes" hence the last character should be s? – GDGDJKJ Jan 28 '19 at 19:32
  • how is that obvious, I put it last? – GDGDJKJ Jan 28 '19 at 19:33
  • 1
    It is obvious it is called first *because of* that result. – Weather Vane Jan 28 '19 at 19:34
  • Arguments are pushed last-to-first on the stack, so it will call `dernier` _first_, then push `s`, then call `debut` – Craig Estey Jan 28 '19 at 19:34
  • 2
    @CraigEstey That's not guaranteed. It could be evaluated in any order. – Osiris Jan 28 '19 at 19:36
  • so it will execute the functions last to first then come back to s? – GDGDJKJ Jan 28 '19 at 19:37
  • @Osiris the 'calling' behviour is unpredictable? – GDGDJKJ Jan 28 '19 at 19:37
  • @Osiris The push order is guaranteed [otherwise, `printf` stops working]. And, it would be an _insane_ compiler to evaluate the arguments out of sequence [for no good reason] because they would have to be stashed in temporaries or stored relative to a changing stack pointer. If you were a compiler writer and I defined a function that took 500 arguments, what would you do? – Craig Estey Jan 28 '19 at 20:04
  • 2
    @CraigEstey It is still not guaranteed by the standard, since it does not mandate the use of a stack. It is also mentioned in [this](https://stackoverflow.com/questions/9566187/function-parameter-evaluation-order) question. – Osiris Jan 28 '19 at 20:08
  • @Osiris I didn't ask you to quote the spec. I asked you to _think_ about what code generation you would do as a compiler writer. Why _would_ you [want to] evaluate the arguments out of order? What would be the justification for that? What extra code would need to be generated? What are the implications of that on an architectural level? – Craig Estey Jan 28 '19 at 20:27
  • 1
    It's true that there's no reason why a compiler shouldn't push arguments to functions once they are evaluated, but unless that information is specifically outlined in the specification for a particular ABI or calling convention, it's still not something you can assume. – Govind Parmar Jan 28 '19 at 20:29
  • 3
    @CraigEstey "Why would you [want to] evaluate the arguments out of order?" --> parallel processing. `debut(s)` and `dernier(s)` are each sent off to be calculated in parallel. Which get does first - it is a coin-flip. No reason for C to constrain the order - that just stifles innovation. C is fast because it allows compilers great latitude. – chux - Reinstate Monica Jan 28 '19 at 20:35

1 Answers1

3

There is no mandated order by the C standard in which arguments to functions are to be evaluated. It's entirely up to the implementation/ABI.

If you're on the ubiquitous x86-32 with a variadic function like printf, you are almost certainly using the calling convention cdecl, where arguments are pushed right-to-left. This means the assembly code near the call site for printf will most probably look something like (pseudo-assembly code):

push @s
call _dernier
push <ret val from _dernier>
push @s
push @s
call _debut
push <ret val from _debut>
push @format_string
call _printf

Note, however, that even with the cdecl calling convention, all that is dictated is the order in which the arguments are to be pushed. They can still be evaluated in any order, as long as they are pushed on the stack right-to-left; you need to look at the generated assembly code from your own compiler to know for sure.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85