I am looking at the C23 draft standard, but I think this would apply in C11 as well. There are several guarantees about sequence points in relation to function calls in C, such as before the return of any library function and between sorting and search algorithm calls to comparison functions. I feel like I am missing something, as my understanding says we don't need these guarantees because we have 6.5.2.2.8:
"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."
This implies as I understand it a sequence point (or the same effect) before the return of any library function and between any comparison function calls. So we don't need those specific guarantees.
Is this a (somewhat confusing) redundancy, or am I missing something?
EDIT: The comments below give two good reasons for the guarantee for library function returns: a library function may be a macro or may be written in assembly. However, the question still stands in relation to the guarantee that comparison function calls are sequence point separated from eachother (and from element movements in the case of sorting). This is only one redundant assurance at this point, so maybe it is just redundant and there is nothing more to it.
return
statements in functions does not. (Semi-speculating, do not have my references conveniently at hand.) – Artichokereturn
statement in them. – Chagringetchar()
that expands to something likebuf_empty ? refill() : buf[i++]
, then doinggetchar() + getchar()
would appear to be UB asi
is modified twice without an intervening sequence point. So unless I'm missing something, either the library implementers have to know that their compiler handles this safely, or use some other method to insert a sequence point. How could the latter be done? – Bushire? :
includes a sequence point, sogetchar() + getchar()
would be fine. – Artichokebuf_empty
and the correspondingi++
, but none in between the twoi++
. gcc and clang both warn about such code as being unsequenced modifications, see godbolt.org/z/d79f6jTqP. I guess the simplest way to fix it for a modern implementation would be an inline function, but I wonder how old implementations did it. – Bushire(real stuff, 0)
. – Artichoke(0,i++,0) + (0,i++,0)
will still result in UB even though each comma operator adds a sequence point, because the twoi++
aren't sequenced in relation to each other. – Salvegetc/putc
don't seem to include a sequence point (and as I mentioned, I'm not sure how they could except by switching to inline functions). Sogetchar() + getchar()
on OpenBSD looks like it actually would cause UB, which I suppose must be a bug. – Bushiregetchar() + getchar()
actually is allowed to be UB. I would need to do(getchar)() + (getchar)()
. – Bushiresqrt(2) + sqrt(3)
is also potentially UB becausesqrt
could be a macro with side effects (onerrno
, for instance). – Bushire#undef getchar
or use(getchar)()
. I know about the stuff with arguments being evaluated exactly once, etc, but that doesn't relate to this point. Maybe I should ask a new question about it. – Bushire