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

时光总嘲笑我的痴心妄想 提交于 2019-12-10 13:53:41

问题


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?

回答1:


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.




回答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.



来源:https://stackoverflow.com/questions/39793885/getc-as-macro-and-c-standard-library-function-definition-coherent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!