在[7.1.4库函数的使用]中 ,我读到:
标题中声明的任何函数可以另外实现为标题中定义的函数式宏…
和
任何实现为宏的库函数的调用都应扩展为仅对其每个参数进行一次计算的代码…
然后对于getc
, [7.21.7.5 getc函数] :
getc函数等效于fgetc,除非它实现为宏,它可能会多次评估流,因此参数永远不应该是带有副作用的表达式。
getc
的定义是:
标准中的定义是连贯的; 你试图解释它们并不是完全一致的。
标准说……
ISO / IEC 9899:2011(C11)标准说(引用了第7.1.4节中的更多材料,并将一个大段的部分分成几个):
除非在以下详细说明中另有明确说明,否则以下每个陈述均适用:……
标头中声明的任何函数可以另外实现为标头中定义的类函数宏,因此如果在包含标头时显式声明了库函数,则可以使用下面显示的技术之一来确保声明不是受到这样一个宏观的影响。
通过将函数的名称括在括号中,可以在本地抑制函数的任何宏定义,因为该名称后面没有左括号,后面表示宏函数名称的扩展。 出于相同的语法原因,即使它也被定义为宏,也允许获取库函数的地址。 185)使用
#undef
删除任何宏定义也将确保引用实际函数。任何实现为宏的库函数的调用都应扩展为仅对其每个参数进行一次计算的代码,必要时用括号完全保护,因此使用任意表达式作为参数通常是安全的。 186)同样,可以在任何可以调用具有兼容返回类型的函数的表达式中调用以下子条款中描述的类似函数的宏。 187)
185)这意味着实现应为每个库函数提供实际函数,即使它还为该函数提供宏。
186)这些宏可能不包含相应函数调用的序列点。
187)因为保留了以下划线开头的外部标识符和一些宏名称,所以实现可以为这些名称提供特殊的语义。 例如,标识符
_BUILTIN_abs
可用于指示abs
函数的内联代码的生成。 因此,适当的头可以指定#define abs(x) _BUILTIN_abs(x)
对于代码生成器将接受它的编译器。 以这种方式,希望保证诸如
abs
的给定库函数将是真实函数的用户可以写入#undef abs
实现的头部是否提供了
abs
或内置实现的宏实现。 由此揭示了函数的原型,其在任何宏定义之前并且被任何宏定义隐藏。
特别注意脚注185的内容。
您还引用了来自§7.21.7.5的getc
定义中的材料:
getc
函数等效于fgetc
,除非它实现为宏,它可能会多次评估stream
,因此参数永远不应该是带有副作用的表达式。
(其中stream
是getc
参数的名称。)
解释标准
你问(略微转述):
确实, getc
宏可能不止一次地评估其fp
参数。 如果§7.1.4说“除非另有说明,任何作为宏实现的库函数的调用都应扩展为仅对其每个参数进行一次计算的代码。”
多次评估其fp
参数的getc
实现可以追溯到stdio的曙光。 所以这并不奇怪,并且基本上没有代码依赖于单一评估或在多重评估下中断。 (谁曾经getc(*fpp++)
像getc(*fpp++)
这样的东西?是的,我可以想出一个例子,甚至不是一个100%做作的例子,但实际上,它很少见。)
真正非常关心的代码总是可以调用fgetc
。 这就是它的用途。
以上就是c/c++开发分享getc()作为宏和C标准库函数定义,连贯吗?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/545309.html