6

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?
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • @Olaf don't understand what you mean... getc(*f++) is safe or not ? Ok, probably unsafe, but contradict 7.1.4. Am I wrong? – Jean-Baptiste Yunès Sep 30 '16 at 14:44
  • Hmm, I might have added a "**the**" in mind when reading the standard ("the stream") which does not exist (just checked the standard, `stream` is the name of the argument). On second thought, it might indeed mean the pointer itself. I'd say 7.1.4 only applies to names which are not required to be a macro, but may be functions. That way identical behaviour is guaranteed without caring if that is a macro or a function. It does not apply for guaranteed macros. Just don't have side-effects of the argument, should not be too much of a problem. – too honest for this site Sep 30 '16 at 15:07
  • Of course it is not a real problem as it is rare to have a border effect as argument. Anyway reading the std, I understand that getc is a function ("getc function"), so 7.1.4 applies, "additionnaly implemented as function-like" + "if it is implemented as a macro" leads me to inconsistency with "evaluates once" and "may evaluate more than once". std give an hint to ensure function call: `(getc)(arg)`. – Jean-Baptiste Yunès Sep 30 '16 at 16:44
  • It is a "function-like macro" as the text implies. But feel free to file a defect report at the C working group. Then, there already might be one. Did you check? – too honest for this site Sep 30 '16 at 16:46
  • There's no defect to report; any attempt to submit a defect on this would be rejected immediately. – Jonathan Leffler Sep 30 '16 at 19:54

2 Answers2

5

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

It's true that a getc macro is likely to evaluate its fp argument more than once. It might be good if §7.1.4 said "Unless otherwise noted, any invocation of a library function that is implemented as a macro shall expand to code that evaluates each of its arguments exactly once."

getc implementations that evaluate their fp argument multiple times go back to the dawn of stdio. So it's no surprise, and there's essentially no code out there that depends on single evaluation or would break under multiple evaluation. (Who ever writes anything like getc(*fpp++)? Yes, I can come up with an example, and not even a 100% contrived one, but really, it's vanishingly rare.)

Code that really, really cares can always call fgetc. That's what it's for.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • Sure it is rare (actually never write something like that, but after all an array of readers read in "parallel" can be useful). But I was reading the standard, and find this (apparently) contradiction. – Jean-Baptiste Yunès Sep 30 '16 at 14:42
  • @Jean-BaptisteYunès Understood. And I'm surprised the Standard doesn't have an "unless otherwise noted" clause, because the situation with `getc` and `putc` macros is significant, and often misunderstood. – Steve Summit Sep 30 '16 at 14:44
  • 2
    The standard does include 'unless explicitly stated otherwise' in 7.1.4 and then explicitly states otherwise in 7.21.7.5. The "it might be good" comment could be upgraded to "Note that §7.1.4 states …". – Jonathan Leffler Sep 30 '16 at 18:01
  • @JonathanLeffler Thanks, that makes me feel better. – Steve Summit Sep 30 '16 at 18:54