So ยง6.5.3.2p1 specifies
The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
Which I think can be taken to mean that &lvalue
is fine for any lvalue that is not in those two categories. And as you mentioned, errno
cannot be declared with the register storage-class specifier, and I think (although am not chasing references to check right now) that you cannot have a bitfield that has type of plain int
.
So I believe that the spec requires &(errno)
to be legal C.
If &errno is legal C, is it required to be constant?
As I understand it, part of the point of allowing errno
to be a macro (and the reason it is in e.g. glibc) is to allow it to be a reference to thread-local storage, in which case it will certainly not be constant across threads. And I don’t see any reason to expect it must be constant. As long as the value of errno
retains the semantics specified, I see no reason a perverse C library could not change &errno
to refer to different memory addresses over the course of a program — e.g. by freeing and reallocating the backing store every time you set errno
.
You could imagine maintaining a ring buffer of the last N errno values set by the library, and having &errno
always point to the latest. I don’t think it would be particularly useful, but I can’t see any way it violates the spec.