views:

331

answers:

5

This is very specific, and a bit difficult to explain, and quite likely impossible, but here goes. Perhaps some C cracks out there have an idea...

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

The naive 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?

A: 

Random thought - avoid direct assignment altogether. The conveniences of shortcuts like making a function call appear as if it were a simple variable has its price.

If necessary, consider #undef errno in places where it is problematic.

Badmotorfinger
I am talking about <errno.h> as part of a standard library. Which means I have no control on how errno is used by client code.
DevSolar
A: 

You could hack together two macros on top of your errno macro to handle the equal sign - e.g. one macro to handle "errno =" and one to handle "= errno". I'm just not sure of how you'd handle whitespace correctly.

Matt Ball
Evil. So simple, but so evil, that I would never have considered that. :-D
DevSolar
It's the kind of thing that makes me love C, yet also makes my skin crawl. Hell, have you seen lists and hashtables implemented with C macros? Easy enough to use, but when you're "iterating" over the list with a macro... whatever you do, don't think about it.
Matt Ball
I don't think this is possible with the C preprocessor. Any suggestions how such a macro should look like?
Christoph
You don't think which part of it is possible? Handling unknown whitespace in a macro, or using macros to write other macros, or something else?
Matt Ball
@Matt: C macros work on token-level, ie there's no way for `errno` and `=` to invoke a single macro
Christoph
Hm. That's a good point. There's got to be a way around that, though. This can't be the first time someone wanted to write a multi-token macro. Any way to, for the purpose of the preprocessor, consider multiple tokens as one?
Matt Ball
@Matt: *Wanting* to write a multi-token macro and actually *writing* one are two very different things ;)
Dan Moulding
+3  A: 

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.

Christoph
+2  A: 

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())
Jonathan Leffler
+1  A: 

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 */
}
AProgrammer