Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getc() as macro and C standard library function definition, coherent?

In [7.1.4 Use of library functions], I read :

Any function declared in a header may be additionally implemented as a function-like macro defined in the header...

and

Any invocation of a library function that is implemented as a macro shall expand to code that evaluates each of its arguments exactly once...

Then for getc, [7.21.7.5 The getc function] :

The getc function is equivalent to fgetc, except that if it is implemented as a macro, it may evaluate stream more than once, so the argument should never be an expression with side effects.

Does the definition of getc:

  • contradicts the library functions definition?
  • the converse?
  • is this an incoherence in the standard?
  • or does this means that if getc is solely implemented (doesn't seems to be compliant but?) as a macro it may evaluate its argument twice?
like image 612
Jean-Baptiste Yunès Avatar asked Sep 30 '16 14:09

Jean-Baptiste Yunès


1 Answers

The definitions in the standard are coherent; your attempted interpretation of them is not completely coherent.

The Standard Says …

The ISO/IEC 9899:2011 (C11) standard says (quoting a bit more of the material from §7.1.4, and breaking parts of one big paragraph into several):

Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: …

Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro.

Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro.185) The use of #undef to remove any macro definition will also ensure that an actual function is referred to.

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.186) Likewise, those function-like macros described in the following subclauses may be invoked in an expression anywhere a function with a compatible return type could be called.187)

185) This means that an implementation shall provide an actual function for each library function, even if it also provides a macro for that function.

186) Such macros might not contain the sequence points that the corresponding function calls do.

187) Because external identifiers and some macro names beginning with an underscore are reserved, implementations may 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. In this manner, a user desiring to guarantee that a given library function such as abs will be a genuine function may write

#undef abs

whether the implementation’s header provides a macro implementation of abs or a built-in implementation. The prototype for the function, which precedes and is hidden by any macro definition, is thereby revealed also.

Note the contents of footnote 185, in particular.

You also quote the material from the definition of getc from §7.21.7.5:

The getc function is equivalent to fgetc, except that if it is implemented as a macro, it may evaluate stream more than once, so the argument should never be an expression with side effects.

(Where stream is the name used for the argument to getc.)

Interpreting the Standard

You ask (slightly paraphrased):

  • Does the definition of getc contradict the library functions definition?

    No. The opening of section §7.1.4 says that 'unless explicitly stated otherwise', and then gives a series of general rules, and then the specification of getc explicitly states otherwise.

  • Does the converse apply?

    No. The opening section of §7.1.4 says that the specification of any particular function can override the generalities from §7.1.4.

  • Is this an incoherence in the standard?

    I see no incoherence here.

  • Or does this mean that if getc is solely implemented as a macro (which doesn't seem to be compliant but…), the macro may evaluate its argument twice?

    1. getc may not be implemented solely as a macro (footnote 185). There must also be an actual function that implements the same functionality. The implementation can be simple:

      int (getc)(FILE *fp) { return getc(fp); }
      
    2. The macro implementing getc is explicitly allowed to evaluate its argument multiple times (but is not required to do so). The specification in §7.21.7.5 explicitly says that it may, and the specification in §7.1.4 explicitly says that §7.21.7.5 is allowed to change the general rule of §7.1.4 that normally forbids such behaviour.

like image 51
Jonathan Leffler Avatar answered Oct 05 '22 18:10

Jonathan Leffler