将 C 标准库中的 C 函数定义为宏 [英] Defining C functions in the C Standard Library as macros

查看:79
本文介绍了将 C 标准库中的 C 函数定义为宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读有关 C 头文件的 The Open Group Base Specifications 和 Posix Programmers 手册页,这句话反复出现以下内容应声明为函数,也可以定义为宏",但我不确定是什么这意味着.从声明的函数中创建宏有什么意义.这不会造成命名空间冲突吗?还有你为什么要这样做?

解决方案

宏从不与其他命名空间冲突;首先处理宏并自动获胜".

标准的C标准库部分的介绍部分,部分7.1 介绍——特别是§7.1.2§7.1.3¶7.1.4 — 涵盖了许多要点.>

有些函数可以通过宏更有效地实现,而不会产生完整函数调用的开销.该标准的规则允许实现为此类函数定义宏,但需要注意一些注意事项.一是宏的参数不能多次使用;另一个是标准中定义的每个函数都必须有一个函数,即使它也被实现为宏.

这些规则允许实施的灵活性,而不会给实施者或实施的用户带来过重的负担.

<块引用>

§7.1.2 标准标题

¶4 ...如果使用时,标题应包含在任何外部声明或定义之外,并且应首先包含在第一次引用它的任何函数或对象之前声明,或者它定义的任何类型或宏.但是,如果声明了标识符或定义在一个以上的标题中,第二个和后续的相关标题可能是包含在对标识符的初始引用之后.该程序不得有任何名称与包含之前当前定义的关键字词法相同的宏标头或扩展标头中定义的任何宏时.

¶5 本节中描述的类对象宏的任何定义都应扩展为必要时由括号完全保护,以便它可以任意分组表达式就好像它是单个标识符一样.

¶6 库函数的任何声明都应具有外部链接.

¶7.1.3 保留标识符

1 每个标题声明或定义其相关子条款中列出的所有标识符,并且可选地声明或定义在其关联的未来库方向中列出的标识符始终保留用于任何用途或用作文件的子条款和标识符范围标识符.

  • 所有以下划线开头的标识符和大写字母或其他下划线始终保留用于任何用途.

  • 以下划线开头的所有标识符始终保留用作标识符在普通名称空间和标签名称空间中都具有文件作用域.

  • 以下任何子条款中的每个宏名称(包括未来的库如果包含任何关联的标头,则保留用于指定的用途;除非另有明确说明(见 7.1.4).

  • 在以下任何子条款中具有外部链接的所有标识符(包括未来库方向)和 errno 始终保留用作标识符外部链接.184)

  • 在以下任何子条款中列出的具有文件范围的每个标识符(包括未来库方向)保留用作宏名称和标识符如果包含任何关联的标头,则同一名称空间中的文件范围.

¶2 不保留其他标识符.如果程序声明或定义了一个标识符保留它的上下文(7.1.4 允许的除外),或定义保留标识符作为宏名称,行为未定义.

¶3 如果程序删除(使用 #undef)第一个标识符的任何宏定义上面列出的组,行为未定义.

184) 带有外部链接的保留标识符列表包括math_errhandlingsetjmpva_copyva_end.

¶7.1.4 库函数的使用

¶1 除非在详细说明中另有明确说明,否则以下每项陈述均适用以下说明:如果函数的参数具有无效值(例如值函数域外,或程序地址空间外的指针,或者一个空指针,或者一个指向不可修改存储的指针,当相应的参数不是常量限定的)或函数不期望的类型(提升后)对于可变数量的参数,行为未定义.如果函数参数是被描述为一个数组,实际传递给函数的指针应该有一个值这样所有的地址计算和对对象的访问(如果指针确实指向这样一个数组的第一个元素)实际上是有效的.任何功能在头文件中声明可以另外实现为定义在 所以如果一个库函数在包含它的头时被显式声明,一个下面显示的技术中的一个可用于确保声明不受这样的宏.函数的任何宏定义都可以通过封闭来局部抑制括号中的函数名称,因为名称后面没有左边表示宏函数名称扩展的括号.对于相同的句法原因,即使库函数也被定义为一个宏.185) 使用 #undef 删除任何宏定义也将确保一个实际功能参考.任何实现为的库函数调用宏应扩展为对每个参数进行一次完全评估的代码必要时由括号保护,因此使用任意的通常是安全的表达式作为参数.186) 同样,在可以在表达式中调用带有可以调用兼容的返回类型.187) 所有列为扩展到的类对象宏整数常量表达式还应适用于#if 预处理指令.

¶2 前提是可以在不引用任何类型定义的情况下声明库函数头,也可以声明函数并使用它而不包括它的关联的标题.

185) 这意味着一个实现应该为每个库函数提供一个实际的函数,即使它还为该函数提供了一个宏.

186) 此类宏可能不包含相应函数调用所做的序列点.

187) 因为外部标识符和一些以下划线开头的宏名称是保留的,实现可以为这些名称提供特殊的语义.例如,标识符_BUILTIN_abs 可用于指示为 abs 函数生成内嵌代码.就这样适当的标题可以指定:

#define abs(x) _BUILTIN_abs(x)

对于其代码生成器将接受它的编译器.通过这种方式,希望保证给定库函数(例如 abs)的用户将是真正的函数可以写

#undef abs

实现的头是否提供了 abs 的宏实现或内置的执行.函数的原型,它位于任何宏之前并被任何宏隐藏定义,从而也被揭示.

重点添加到 ¶7.1.4

这些规则概述了实现者(编译器,尤其是 C 库)与使用该实现的程序员之间的条约中的要点.

I have been reading The Open Group Base Specifications and the Posix Programmers man pages on C headers and this phrase reappears a lot "The following shall be declared as functions and may also be defined as macros" and I am not exactly sure what that means. What is the point of creating a macro out of a declared function. Wouldn't that just create a namespace conflict? Also why would you even want to do that?

解决方案

Macros never conflict with other namespaces; macros are processed first and automatically 'win'.

The introduction section of the C Standard Library section of the standard, section 7.1 Introduction — and particularly §7.1.2, §7.1.3, and ¶7.1.4 — cover many of the points.

There are some functions that might be implemented more efficiently by a macro without incurring the overhead of a full function call. The rules of the standard allow an implementation to define macros for such functions, subject to a number of caveats. One is that the arguments to the macro may not be used more than once; another is that there must be a function for every function defined in the standard, even if it is also implemented as a macro.

The rules allow for flexibility in implementation without over-burdening the implementors or the users of the implementation.

§7.1.2 Standard headers

¶4 … If used, a header shall be included outside of any external declaration or definition, and it shall first be included before the first reference to any of the functions or objects it declares, or to any of the types or macros it defines. However, if an identifier is declared or defined in more than one header, the second and subsequent associated headers may be included after the initial reference to the identifier. The program shall not have any macros with names lexically identical to keywords currently defined prior to the inclusion of the header or when any macro defined in the header is expanded.

¶5 Any definition of an object-like macro described in this clause shall expand to code that is fully protected by parentheses where necessary, so that it groups in an arbitrary expression as if it were a single identifier.

¶6 Any declaration of a library function shall have external linkage.

¶7.1.3 Reserved identifiers

1 Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

  • Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).

  • All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage.184)

  • Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.

¶2 No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.

¶3 If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined.

184) The list of reserved identifiers with external linkage includes math_errhandling, setjmp, va_copy, and va_end.

¶7.1.4 Use of library functions

¶1 Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined. If a function argument is described as being an array, the pointer actually passed to the function shall have a value such that all address computations and accesses to objects (that would be valid if the pointer did point to the first element of such an array) are in fact valid. 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) All object-like macros listed as expanding to integer constant expressions shall additionally be suitable for use in #if preprocessing directives.

¶2 Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.

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.

Emphasis added to ¶7.1.4

These rules outline the main points in the treaty between the implementor (of the compiler and, more especially, the C library) and the programmer using that implementation.

这篇关于将 C 标准库中的 C 函数定义为宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆