Comment by 112233

1 month ago

Thanks, I did read it! Things like footnote 236: "This means that an implementation is required to provide an actual function for each library function, even if it also provides a macro for that function", where macro is shown to use compiler builtin as an example.

Again, could you please explain how compiler can decide to remove call to a function in an external dynamically loaded library, that is not known at compile time, simply based on the name of the function (i.e. not because the call is unreachable)? I do not see any such language in the standard.

And yes, calling unknown function from a dynamically loaded library totally is a side effect.

> Again, could you please explain how compiler can decide to remove call to a function in an external dynamically loaded library, that is not known at compile time, simply based on the name of the function (i.e. not because the call is unreachable)? I do not see any such language in the standard.

> And yes, calling unknown function from a dynamically loaded library totally is a side effect.

The thing is that malloc/free aren't "unknown function[s]". From the C89 standard:

> All external identifiers declared in any of the headers are reserved, whether or not the associated header is included.

And from the C23 standard:

> All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage

malloc/free are defined in <stdlib.h> and so are reserved names, so compilers are able to optimize under the assumption that malloc/free will have the semantics dictated by the standard.

In fact, the C23 standard explicitly provides an example of this kind of thing:

> Because external identifiers and some macro names beginning with an underscore are reserved, implementations can provide special semantics for such names. For example, the identifier _BUILTIN_abs could be used to indicate generation of in-line code for the abs function. Thus, the appropriate header could specify

    #define abs(x) _BUILTIN_abs(x)

> for a compiler whose code generator will accept it.

Only answering the "side effect" part as the rest was answered already.

What a side effect is, is explained in "5.1.2.3". Calling function is only a side effect when the function contains a side effect, such as modifying an object, or a volatile access, or I/O.