Standard C (in all its versions, as far as I know) allows any standard library function to also be defined as a macro. In the current C standard, that's buried in §7.1.4 (Use of Library Functions), paragraph 1:
Any function declared in a header may be additionally implemented as a function-like macro defined in the header… Any invocation of a library function that is implemented as a macro shall expand to code that evaluates each of its arguments exactly once, fully protected by parentheses where necessary, so it is generally safe to use arbitrary expressions as arguments.
The macros may be defined by a standard library implementation in order to provide efficiencies (although this is less important than it used to be, now that most compiler will inline functions), but the functions also need to be defined as functions with exactly the same semantics, which means that you can use the function without including the header (as long as you provide the correct function prototype) and that you can take the address of the function.
And, as indicated in the second sentence I quoted, you don't have to worry about the possible odd side effects of macros, such as multiple evaluation of their arguments -- unless the description of the function indicates otherwise. (One such function is getc
, which is semantically identical to fgetc
except that getc
is allowed to implemented as a macro which does evaluate its argument more than once.)
It was never the case that these functions were only implemented as macros (at least, not in conformant standard libraries). But there was a time when it was so common to also implement simple functions as macros that some people just counted on the macros existing. Or talked about them as though that was the only implementation.
None of this is the case in C++. C++ requires functions to be functions (and macros to be macros), and the functions are in namespaces. That didn't make C++ incompatible with C; it was merely necessary for the C++ headers which declare functions shared with C (that is, the ones whose names start with c
) to #undef
all the (potential) macros definitions after including the corresponding C header.