Thoughts on Implementing errno as a Macro

WG 14 Document numberN1308
WG 21 Document numberN2604=08-0114
Date2008-04-25
ProjectsProgramming Languages C & C++
ReferenceISO/IEC IS 9899:1999
ReferenceISO/IEC IS 14882:2003(E)
Reply toNick Stoughton
USENIX Association
nick@usenix.org

Background

SC22 WG14 N1257 describes an inconsistency in the wording for <errno.h>. In p1, <errno.h> defines several macros. In p2 "The macros are ... errno". But later in p2 "It is unspecified whether errno is a macro or an identifier declared with external linkage." So is errno a macro or not?

If we consider existing practice very old implementations, and some current embedded implmentations, have errno as a simple integer variable. On the other hand, any implementation that has support for some form of multi-threading implements errno as a macro, expanding into a different modifiable lvalue for each thread. It could also, potentially, be implemented using some form of thread local storage.

N1257 took these factors into consideration, and proposed wording that removed the ambiguity but preserved all existing implementations (no quiet changes). The paper was considered during the Kona meeting, and N1270 (the Kona minutes) stated

C++ is requiring that they be macros. It would not be a bad thing if we did likewise. Make it required that errno is a macro, rather than unspecified.

The current wording in SC22 WG21 N2588 (the C++ Working Draft), states:

The header <cerrno> is described in (Table 29). Its contents are the same as the POSIX header <errno.h>, except that errno shall be defined as a macro. [ Note: The intent is to remain in close alignment with the POSIX standard. -end note ]

In turn, POSIX defines errno as

The <errno.h> header shall provide a declaration or definition for errno. The symbol errno shall expand to a modifiable lvalue of type int. It is unspecified whether errno is a macro or an identifier declared with external linkage. 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.

These are the same words proposed in WG14 N1257. The stated goal (in a note) of C++ is to align with POSIX, but POSIX does not require that errno be a macro.

The Way Forward

There are two possible solutions to the inconsistencies that exist both within the C standard and between the C, C++ and POSIX standards.
  1. Use the words in N1257 to fix the inconsistency in C. Use the words suggested below to modify the C++ draft to align it with both POSIX and C, both of which are already stated goals in C++.
  2. Draft new words to force errno to be a macro in C. Use similar words to modify POSIX. Note although POSIX is undergoing revision at this time, it has completed FCD and is going to DIS within the next month or two. Such a change would need to wait for the next revision.

For these reasons, this paper, while requested by WG 14, is being submitted to both WG14 and WG21 and contains proposed changes to the C++ working draft. It also seeks to try to handle any potential conflict between C++ and POSIX over the content of the POSIX header <errno.h>.

Proposed Wording for C++

19.3 Error numbers [errno]

The header <cerrno> is described in (Table 29). Its contents are the same asaligned with the POSIX header <errno.h>, except that errno shall be defined as a macro; any conflict between the requirements described here and the ISO POSIX standard is unintentional. This standard defers to the POSIX standard. [ Note: The intent is to remain in close alignment with the POSIX standard. -end note ] Table 29: Header synopsis
TypeName(s)
Macros: ECONNREFUSED EIO ENODEV ENOTEMPTY ERANGE
E2BIG ECONNRESET EISCONN ENOENT ENOTRECOVERABLE EROFS
EACCES EDEADLK EISDIR ENOEXEC ENOTSOCK ESPIPE
EADDRINUSE EDESTADDRREQ ELOOP ENOLCK ENOTSUP ESRCH
EADDRNOTAVAIL EDOM EMFILE ENOLINK ENOTTY ETIME
EAFNOSUPPORT EEXIST EMLINK ENOMEM ENXIO ETIMEDOUT
EAGAIN EFAULT EMSGSIZE ENOMSG EOPNOTSUPP ETXTBSY
EALREADY EFBIG ENAMETOOLONG ENOPROTOOPT EOVERFLOW EWOULDBLOCK
EBADF EHOSTUNREACH ENETDOWN ENOSPC EOWNERDEAD EXDEV
EBADMSG EIDRM ENETRESET ENOSR EPERM errno
EBUSY EILSEQ ENETUNREACH ENOSTR EPIPE
ECANCELED EINPROGRESS ENFILE ENOSYS EPROTO
ECHILD EINTR ENOBUFS ENOTCONN EPROTONOSUPPORT
ECONNABORTED EINVAL ENODATA ENOTDIR EPROTOTYPE
SEE ALSO: ISO C subclause 7.1.4, 7.2, Amendment 1 subclause 4.3.

The <cerrno> header also provides a declaration or definition for errno. The symbol errno shall expand to a modifiable lvalue of type int. It is unspecified whether errno is a macro or an identifier declared with external linkage. 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.

The value of errno is zero at program start-up, but is never set to zero by any library function. The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

Proposed wording for C

The following is drawn from the wording suggested in WG14 N1257, and is repeated here for clarity with minor editorial changes. In addition, this is now presented as change marked differences (using strikethrough etc) to make it easier to understand the change.

In 7.5, change para 2 to read:

The macros are
EDOM
EILSEQ
ERANGE
which expand to integer constant expressions with type int, distinct positive values, and which are suitable for use in #if preprocessing directives.; and
errno
which
The <errno.h> header also provides a declaration or definition for errno. The symbol errno expands to a modifiable lvalue175) that has type int, the value of which is set to a positive error number by several library functions. It is unspecified whether errno is a macro or an identifier declared with external linkage. 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.