检测宏的用法? (错误)

时间:2009-08-28 14:03:29

标签: c macros c-preprocessor

这是非常具体的,有点难以解释,而且很可能不可能,但是这里有。

我想实现< errno.h> 。 (我的爱好项目正在实施一个标准的 C 库。)

这种天真的方式是:

// in <errno.h>
extern int errno;

// in some .c file
int errno = 0;

这很有效。但它有一个缺点:如果调用数学库函数,总是必须在执行后查询FPU状态以适当地设置errno。这使得FPU在数学繁重的应用程序中停滞不前。

C 标准通过将其设为宏来支持errno的延迟评估:

int * __errno();
#define errno *__errno()

这样,errno仅在实际请求其值时“设置”:

// "__errno()" returns the location of the current errno value,
// the "errno" macro turns it into a value.
x = errno;

在库的其余部分给出一些逻辑,只有在调用的最后一个库函数实际上是使用 FPU,和{{1}的值时,才需要查询FPU状态。实际上是请求

到目前为止,一切都很好。但另一种方法是让我头疼:

errno

根本不要求errno = 0; 的值。 但是errno不知道这一点,并且如果调用的最后一个库函数正在使用FPU,它将查询FPU状态。

现在我没有办法避免这种情况(即__errno()宏或errno函数以某种方式有所不同,具体取决于它们是否用于左侧或右侧赋值算子),我几乎满足于接受这个。

但也许你们中的任何一个人都有一个好主意?

3 个答案:

答案 0 :(得分:4)

这里没有精彩的想法,但允许通过函数调用实现afaik errno,以使标准库的线程安全实现成为可能。我不认为懒惰地查询FPU是一个好主意:在这种情况下你将如何避免不一致:

  • 设置errno
  • 设置错误标志的浮点运算
  • 获取errno
  • 获得标志

呼叫__errno()是否应该清除标志?

根据标准,errno是否必须由数学函数设置取决于math_errhandling的值(具体而言,math_errhandling & MATH_ERRNO)。

我要做的是通过预处理程序指令使错误报告可选,并允许程序员在编译时设置math_errhandling的值。这意味着数学函数不能事先静态编译,但必须驻留在标题中,无论如何,这可能是一个好主意,允许没有链接时优化的编译器内联这些函数。

答案 1 :(得分:2)

你在这里有一个很好的分析,为什么整个errno机制是如此令人不满意。您也可以在Kernighan的“标准C库”中找到类似的分析。

线程安全实现也需要errno的函数形式,其中不同的线程具有通过特定于线程的errno访问的单独错误值。

为了安全起见,您的宏应该在它周围加上括号:

#define errno (*__errno())

答案 2 :(得分:1)

更多评论而不是答案,但如果没有代码格式化,则无法理解。

如果懒洋洋地检查FPU标志,那么你将如何在这里获得正确的行为(数学函数是特殊的,因为它们保证在没有问题时不会修改errno)?

errno = 0;
x = acos(y);
z = <exp>;
if (errno != 0) {
   /* can't come here even if y is a valid argument but <exp> modified the flags if it didn't call any functions */
}