25

In C and C++, is there a fixed order for evaluation of parameter to the function? I mean, what do the standards say? Is it left-to-right or right-to-left? I am getting confusing information from the books.

Is it necessary that function call should be implemented using stack only? What do the C and C++ standards say about this?

5
  • 6
    The standards don't specify it. The order could even be changing randomly at runtime (but no implementation do that, AFAIK). Mar 5, 2012 at 11:56
  • 4
    Small note - you could think that a comma is a sequence point, which would enforce left-to-right ordering. But the comma operator is a sequence point, not the comma that separates function parameters.
    – ugoren
    Mar 5, 2012 at 12:18
  • If you're relying upon it, then your code may be difficult to read, to reason about, and to maintain.
    – Peter Wood
    Mar 5, 2012 at 12:31
  • 1
    What information is missing in the countless of duplicated questions about this here on SO?
    – PlasmaHH
    Mar 5, 2012 at 12:39
  • Do not tag your question with C and C++ at the same time if it is not about differences, similarities, code that should work on both or something like that. Sep 21, 2020 at 14:12

5 Answers 5

36

C and C++ are two completely different languages; don't assume the same rules always apply to both. In the case of parameter evaluation order, however:

C99:

6.5.2.2 Function calls
...
10 The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

[Edit] C11 (draft):

6.5.2.2 Function calls
...
10 There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.94)
...
94) In other words, function executions do not ‘‘interleave’’ with each other.

C++:

5.2.2 Function call
...
8 The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.

Neither standard mandates the use of the hardware stack for passing function parameters; that's an implementation detail. The C++ standard uses the term "unwinding the stack" to describe calling destructors for automatically created objects on the path from a try block to a throw-expression, but that's it. Most popular architectures do pass parameters via a hardware stack, but it's not universal.

[Edit]

I am getting confusing information from the books.

This is not in the least surprising, since easily 90% of books written about C are simply crap.

While the language standard isn't a great resource for learning either C or C++, it's good to have handy for questions like this. The official™ standards documents cost real money, but there are drafts that are freely available online, and should be good enough for most purposes.

The latest C99 draft (with updates since original publication) is available here. The latest pre-publication C11 draft (which was officially ratified last year) is available here. And a publicly availble draft of the C++ language is available here, although it has an explicit disclaimer that some of the information is incomplete or incorrect.

4
  • "The C++ standard uses the term "unwinding the stack" - I agree with you, and I think that "unwinding the stack" refers to backing out through the call stack, which conceptually is a stack regardless of how it's actually represented in memory, and also regardless of how the addresses of function parameters relate to any structures the implementation might use to represent the call stack. So the term "unwinding the stack" doesn't prejudice the calling convention, and indeed many calling conventions use at least some registers where possible. Oct 2, 2012 at 9:06
  • 6
    since easily 90% of books written... Did you know also that 95% of statements made that use statistics to assert their truth are made up on the spot, and are completely useless except for characterizing other statistics? (nice answer by the way)
    – ryyker
    Aug 20, 2015 at 15:08
  • @John Bode "C and C++ are two completely different languages; don't assume the same rules always apply to both. " C++ compilers compile C codes, so we can say C rules appy to C++, can't we?
    – user4612022
    Feb 12, 2017 at 18:13
  • 3
    @thoron: No. There are plenty of legal C programs that are not legal C++ programs, and there are legal C programs that are also legal C++ programs, but have different semantics. The two languages share a lot in common, but there are areas where they differ significantly.
    – John Bode
    Feb 12, 2017 at 19:39
9

Keeping it safe: the standard leaves it up to the compiler to determine the order in which arguments are evaluated. So you shouldn't rely on a specific order being kept.

9
  • 1
    I would upvote you if you removed the second paragraph. I just think that confuses matters. Mar 5, 2012 at 11:58
  • 1
    @sad: you can't "work around" anything. Don't come back complaining when the compiler optimized your code into doing things wrong, because you relied on unreliable assumptions. Mar 5, 2012 at 12:09
  • 3
    The second paragraph is simply wrong. Even if the calling convention is to push the parameters in right-to-left order, instruction reordering can change the order of evaluation.
    – interjay
    Mar 5, 2012 at 12:10
  • 1
    @R.MartinhoFernandes if observed behavior is affected, I'm pretty sure the compiler can't call goo before foo in my snippet. Mar 5, 2012 at 12:10
  • 1
    @Luchian that's not the second paragraph though. Mar 5, 2012 at 12:11
5

In C/C++ is there a fixed order for evaluation of parameter to the function. I mean what does standards says is it left-to-right or right-to-left . I am getting confusing information from the books.

No, the order of evaluation of function parameters (and of two sub-expressions in any expression) is unspecified behaviour in C and C++. In plain English that means that the left-most parameter could be evaluated first, or it could be the right-most one, and you cannot know which order that applies for a particular compiler.

Example:

static int x = 0;

int* func (int val)
{
  x = val;
  return &x;
}

void print (int val1, int val2)
{
  cout << val1 << " " << val2 << endl;
}

print(*func(1), *func(2));

This code is very bad. It relies of order of evaluation of print's parameters. It will print either "1 1" (right-to-left) or "2 2" (left-to-right) and we cannot know which. The only thing guaranteed by the standard is that both calls to func() are completed before the call to print().

The solution to this is to be aware that the order is unspecified, and write programs that don't rely on the order of evaluation. For example:

int val1 = *func(1);
int val2 = *func(2);
print(val1, val2); // Will always print "1 2" on any compiler.

Is it necessary that function call should be implemented using stack only. what does C/C++ standards says about this.

This is known as "calling convention" and nothing that the standard specifies at all. How parameters (and return values) are passed, is entirely up to the implementation. They could be passed in CPU registers or on the stack, or in some other way. The caller could be the one responsible for pushing/popping parameters on the stack, or the function could be responsible.

The order of evaluation of function parameters is only somewhat associated with the calling convention, since the evaluation occurs before the function is called. But on the other hand, certain compilers can choose to put the right-most parameter in a CPU register and the rest of them on the stack, as one example.

0

Just only to speak for C language, the order of evaluation inside the function parameters depend on compiler. from The C Programming Language of Brian Kernighan and Dennis Ritchie;

Similarly, the order in which function arguments are evaluated is not specified, so the statement

printf("%d %d\n", ++n, power(2, n)); /*WRONG */

can produce different results with different compilers, depending on whether n is incremented before power is called. The solution, of course, is to write

++n;

printf("%d %d\n", n, power(2, n));

0

As far as I know, the function printf has an exception here.

For an ordinary function foo, the order of evaluation of foo(bar(x++), baz(++x)) is undefined. Correct! However printf, being an ellipsis function has a somewhat more definite order of evaluation.

The printf in the standard library, in fact, has no information about the number of arguments that has been sent to. It just tries to figure out the number of variables from the string placeholders; namely, from the number of percent operators (%) in the string. The C compiler starts pushing arguments from the very right towards left; and the address of the string is passed as a last argument. Having no exact information about the number of arguments, printf evaluates the last address (the string) and starts replacing the %'s (from left to right) with values of the corresponding addresses in the stack. That is, for a printf like below;

{
    int x = 0;
    printf("%d %d %f\n", foo(x), bar(x++), baz(++x));
}

The order of evaluation is:

  1. x is incremented by 1,
  2. function baz is called with x = 1; return value is pushed to the stack,
  3. function bar is called with x = 1; return value is pushed to the stack,
  4. x is incremented by 1,
  5. function foo is called with x = 2; return value is pushed to the stack,
  6. the string address is pushed to the stack.

Now, printf has no information about the number of arguments that has been sent to. Moreover, if -Wall is not issued in compilation, the compiler will not even complain about the inconsistent number of arguments. That is; the string may contain 3 %'s but the number of arguments in the printf line can be 1, 2, 3, 4, 5 or even can contain just the string itself without any arguments at all.

Say, the string has 3 placeholders and you've send 5 arguments (printf("%d %f %s\n", k1, k2, k3, k4, k5)). If compilation warning is turned off, the compiler will not complain about excessive number of arguments (or insufficient number of placeholders). Knowing the stack address, printf will;

  1. treat the first integer width in the stack and print it as an integer (without knowing whether it is an integer or not),
  2. treat the next double width in the stack and print it as a double (without knowing whether it is a double or not),
  3. treat the next pointer width in the stack as a string address and will try to print the string at that address, until it finds a string terminator (provided, the address pointed to belong to that process; otherwise raises segmentation error).
  4. and ignore the remaining arguments.

Not the answer you're looking for? Browse other questions tagged or ask your own question.