Home > Software engineering >  C order of evaluation: function designator vs actual arguments
C order of evaluation: function designator vs actual arguments

Time:12-20

It is well known that the evaluation order of actual arguments varies from one C compiler to the other. But as ISO 9899:1999 states in §6.5.2.2.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.

I never came across a compiler which generates code where the function designator is evaluated after or interleaved with the actual arguments since I started using C in the eighties. Is it therefore "safe" to use the following (simplified) code in an application:

void* self;
(self = getPointerToObject())->classPtr->methodX(self);

or is it really necessary to do something like:

void* self;
int (*methodPtr)(void*);
(methodPtr = (self = getPointerToObject())->classPtr->methodX, methodPtr(self));

to get an explicit sequence point between the function designator and argument evaluation (at some performance cost)?

Are there C compilers out there which would generate code where the first code snipped would not work (i.e. feed an undefined self argument to methodX)?

CodePudding user response:

C99 defines the following sequence points:

  • The call to a function, after the arguments have been evaluated (6.5.2.2).
  • The end of the first operand of the following operators: logical AND && (6.5.13); logical OR || (6.5.14); conditional ? (6.5.15); comma , (6.5.17).
  • The end of a full declarator: declarators (6.7.5);
  • The end of a full expression: an initializer (6.7.8); the expression in an expression statement (6.8.3); the controlling expression of a selection statement (if or switch) (6.8.4); the controlling expression of a while or do statement (6.8.5); each of the expressions of a for statement (6.8.5.3); the expression in a return statement (6.8.6.4).
  • Immediately before a library function returns (7.1.4).
  • After the actions associated with each formatted input/output function conversion specifier (7.19.6, 7.24.2).
  • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call (7.20.5).

Conclusion: It is not safe. The fact that it works by accident when you tested it doesn't mean all compilers will always behave like that.

CodePudding user response:

This has not much to do with functions but with parentheses.

int x = 5, y;
x = (y = x*x) * y;

This "works" by printing 625, but there is a sequence point warning. Like OK I'll do y in the parentheses first, but that is just me.

  • Related