R
regis
Greetings,
my question relates to function calls with hidden side effects,
that are used as arguments of another function, particularly
in regard to the two following sections found in the draft
[3.3.2.2 Function calls] "The order of evaluation of the function
designator, the arguments, and subexpressions within the arguments is
unspecified."
[2.1.2.3 Program execution] "... at sequence points, all side effects of
previous evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place."
For the sake of the exposition, let assume the type Pair,
and a function MakePair() returning a Pair:
typedef struct { int first, second; } Pair;
Pair MakePair (int first, int second) {
Pair pair;
pair.first= first;
pair.second= second;
return pair;
}
Assume 666 and 777 are the next two integers returned by rand(),
and consider the call: Pair rand_pair= MakePair (rand(), rand());
rand() probably does some side-effects on some global variables
to prepare for its next call, which leads me to wonder what to
think about the behavior or the call:
1) side-effects of both rand() calls may interleave, behavior is
undefined and program may break ?
2) rand_pair is either (Pair){ 666, 777 } or (Pair){ 777, 666 }
at the discretion of the implementation, i.e., the order of evaluation
of both rand() calls is unspecified, but we end with a random pair,
and all run smoothly in all rand() calls ?
3) any other scenario ?
Similar scenarios could be made with functions unsuspectingly touching
errno through other functions deeper in their code, or with functions
unsuspectingly using static data through deeper calls to, say, ctime().
my question relates to function calls with hidden side effects,
that are used as arguments of another function, particularly
in regard to the two following sections found in the draft
[3.3.2.2 Function calls] "The order of evaluation of the function
designator, the arguments, and subexpressions within the arguments is
unspecified."
[2.1.2.3 Program execution] "... at sequence points, all side effects of
previous evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place."
For the sake of the exposition, let assume the type Pair,
and a function MakePair() returning a Pair:
typedef struct { int first, second; } Pair;
Pair MakePair (int first, int second) {
Pair pair;
pair.first= first;
pair.second= second;
return pair;
}
Assume 666 and 777 are the next two integers returned by rand(),
and consider the call: Pair rand_pair= MakePair (rand(), rand());
rand() probably does some side-effects on some global variables
to prepare for its next call, which leads me to wonder what to
think about the behavior or the call:
1) side-effects of both rand() calls may interleave, behavior is
undefined and program may break ?
2) rand_pair is either (Pair){ 666, 777 } or (Pair){ 777, 666 }
at the discretion of the implementation, i.e., the order of evaluation
of both rand() calls is unspecified, but we end with a random pair,
and all run smoothly in all rand() calls ?
3) any other scenario ?
Similar scenarios could be made with functions unsuspectingly touching
errno through other functions deeper in their code, or with functions
unsuspectingly using static data through deeper calls to, say, ctime().