简体   繁体   中英

C order of evaluation: function designator vs actual arguments

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 (ie feed an undefined self argument to methodX)?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM