Home > OS >  C: How to name a struct field `errno`?
C: How to name a struct field `errno`?

Time:05-12

I want to define a struct:

struct error
{
    int errno;
    /* other information */
};

And then I want my code to have error paths that look like this:

struct error my_error;
my_error.errno = errno;
/* set other fields on the error */

But if the same translation unit includes #include <errno.h>, then errno is normally a macro which gets replaced with something else.

Assuming you actually need to access errno in that translation unit so you can't just undefine it, is there a way to still have that struct field name?

I don't care if it's by suppressing the expansion for a specific token, or by somehow getting the errno token to get generated by other macro expansions which don't then expand further, or whatever method.

Ultimately it doesn't matter and I can just name the field something else like error or error_number instead. I just don't like being unable to name things what seems to be the most appropriate name.

CodePudding user response:

Because you commented:

I want to achieve source code where stuff like this is possible ... because I think errno is self-evidently the most clear and optimal name for that field and it's offensive that C isn't letting me use the most appropriate name for something.

It's generally a bad idea to override common identifiers that are part of the language, because it confuses people. And, it will confuse yourself at some point, when you've forgotten you did this; so it's not even advisable in private own projects.

Writing meaningful bug free code is already a very demanding task for humans. Tricks like this make things more difficult to understand. Meaning matters the most in programming!

Then, I don't think that errno is such a great name that asks to be used elsewhere:

  • consists of two abbreviated parts: err and no.
  • doesn't use common camel-case errNo
  • good alternatives are easy/obvious (e.g. errorNumber)
  • in the example I see struct error, not struct err, so it seems you don't like the abbr. err that much

Finally, if errno is a macro, a line like: my_error.errno = errno;, which is at the heart of why you want this, will never be possible because the CPP won't be able to differentiate between the two errnos. QED.

CodePudding user response:

If a macro definition is suppressed in order to access an actual object, or a program defines an identifier with the name errno, the behavior is undefined.

https://port70.net/~nsz/c/c11/n1570.html#7.5

CodePudding user response:

Using errno as an identifier for a user defined object is not a good idea albeit not explicitly forbidden by the C Standard:

7.1.3 Reserved identifiers

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 potentially reserved identifiers (including ones listed in the future library directions) that are provided by an implementation are reserved for any use. No other potentially reserved identifiers are reserved.
— 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.
— 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.

Furthermore, errno is specified in 7.5 Errors <errno.h> as being defined as a macro.

Hence if you do not include <errno.h> or if you undefine errno, you can name a struct member errno, but for reasons explained in other answers, it is probably a bad idea.

You cannot use my_error.errno = errno; to set your structure member because you must the macro errno must be undefined for the member to be accessed.

Here is a possible, albeit not recommended approach:

#include <errno.h>

int get_errno(void) { return errno; }

#undef errno

struct error {
    int errno;
    /* other information */
};

int myfunction(const char *filename, struct error *errorp) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        errorp->errno = get_errno();
        return -1;
   }
   fclose(fp);
   return 0;
}

CodePudding user response:

You can use #undef to undefine a preprocessor macro, for example : https://ideone.com/le9aTz

So #undef errno should work.

Note that of course you won't be able to use the original definition of errno after the #undef. If your struct error is defined in one of your header files, any file including that header will not be able to use the original definition of errno either.

All in all it's probably better to rename your member variable something different.

  • Related