检测宏的使用? (错误号)

发布于 2024-08-02 18:30:45 字数 1101 浏览 2 评论 0原文

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

我想实现 。 (我的爱好项目是实现一个标准 C 库。)

简单的方法是:

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

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

这可行。但它有一个缺点:如果调用数学库函数,它总是必须在执行后查询 FPU 状态以设置适当的 errno 。这会导致 FPU 在数学运算量大的应用程序中停滞不前。

C 标准通过将 errno 设为宏来支持对 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、和 errno 的值时,才需要查询 FPU 状态 实际上是请求的

到目前为止,一切都很好。但相反的情况却让我头疼:

errno = 0;

根本没有请求 errno 的值。 但是 __errno() 不知道这一点,并且如果最后调用的库函数正在使用 FPU,则会查询 FPU 状态。

现在我没有找到一种方法避免这种情况(即,让 errno 宏或 __errno() 函数以某种方式工作,具体取决于它们是用于赋值运算符的左侧还是右侧),我几乎满足于接受这一点。

但也许你们中的任何一个 SO'ers 有一个绝妙的主意?

This is very specific, and a bit difficult to explain, and quite likely impossible, but here goes.

I want to implement <errno.h>. (My hobby project is implementing a Standard C library.)

The naïve way to go about it is:

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

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

This works. But it has one disadvantage: If a math library function is called, it always has to query the FPU status after execution to set errno as appropriate. This stalls the FPU in math-heavy applications.

The C standard endorses lazy evaluation of errno by making it a macro instead:

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

This way, errno is only "set" when its value is actually requested:

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

Given some logic in the rest of the library, the FPU status needs only be queried if the last library function called was actually one using the FPU, and the value of errno is actually requested.

So far, everything is fine. But it's the other way around that is giving me headaches:

errno = 0;

The value of errno is not requested at all. But __errno() does not know that, and will query the FPU status if the last library function called was using the FPU.

Right now I don't see a way to avoid that (i.e., have the errno macro or the __errno() function somehow work differently depending on whether they are used to the left or the right of the assignment operator), and am almost content to accept this.

But perhaps any of you SO'ers has a brilliant idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眉黛浅 2024-08-09 18:30:45

这里没有什么绝妙的想法,但是 afaik errno 可以通过函数调用来实现,以使标准库的线程安全实现成为可能。我不认为延迟查询 FPU 是一个好主意:如何避免在这种情况下出现不一致:

  • set errno
  • float-point ops which set error flags
  • get errno
  • get flags

调用 __errno() 是否应该清除标志?

根据标准,数学函数是否必须设置errnomath_errhandling的值决定(具体来说,math_errhandling & MATH_ERRNO)。

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

No brilliant ideas here, but afaik errno is allowed to be implemented via function calls to make thread-safe implementations of the standard library possible. I don't think querying the FPU lazily is a good idea: How will you avoid inconsistency in situations like this:

  • set errno
  • floating-point ops which set error flags
  • get errno
  • get flags

Should a call to __errno() clear the flags or not?

According to the standard, whether or not errno has to be set by math functions is determined by the value of math_errhandling (specifically, math_errhandling & MATH_ERRNO).

What I would do is make the error reporting optional via preprocessor directives and allow the programmer to set the value of math_errhandling at compile time. This would mean that the math functions can't be compiled statically beforehand but have to reside in a header, which might be a good idea anyway to allow compilers without link-time optimizations to inline these functions.

如歌彻婉言 2024-08-09 18:30:45

这里对为什么整个 errno 机制如此不令人满意进行了相当好的分析。您也可以在 Kernighan 的“标准 C 库”中找到类似的分析。

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

为了安全起见,你的宏应该有括号:

#define errno (*__errno())

What you have here is a fairly good analysis of why the whole errno mechanism is so unsatisfactory. You could find a similar analysis in Kernighan's "The Standard C Library" too.

The functional form of errno is also needed for thread-safe implementations, where different threads have separate error values accessed via a thread-specific errno.

Your macro should probably have parentheses around it for safety:

#define errno (*__errno())
时光瘦了 2024-08-09 18:30:45

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

如果您懒惰地检查 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 */
}

More a comment than an answer, but without code formatting it would not be understandable.

If you check lazily the FPU flags, how would you have the correct behavior here (the math functions are special in that they are guaranteed not to modify errno when there is no problem)?

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 */
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文