简体   繁体   中英

Does C99 (and later) 7.1.3 Reserved identifiers miss "external"?

C89, 4.1.2 Standard headers (emphasis added):

All external identifiers that begin with an underscore are reserved.

C99 (and later), 7.1.3 Reserved identifiers , 1 (emphasis added):

All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

Rationale for C, 7.1.3 Reserved identifiers, 25 (emphasis added):

Also reserved for the implementor are all external identifiers beginning with an underscore, and all other identifiers beginning with an underscore followed by a capital letter or an underscore.

So, per C99 (and later), in:

typedef int _t;        // non-reserved in C89, reserved in C99 (and later)
static int _f(int x);  // non-reserved in C89, reserved in C99 (and later)

(declared at file scope) the _t and _f are reserved, which contradicts with Rationale and with C89.

Does it mean that C99 (and later) misses "external" in 7.1.3 Reserved identifiers: "All external identifiers that..."?

The table:

                                is _x reserved ?

                                C89     C99 (and later)
scope - linkage
function - external             n/a     n/a
function - internal             n/a     n/a
function - none                 no      no
file - external                 yes     yes**
file - internal                 no      yes**
file - none                     no      yes**
block - external                yes     no*
block - internal                n/a     n/a
block - none                    no      no
function prototype - external   n/a     n/a
function prototype - internal   n/a     n/a
function prototype - none       no      no

where * is a possible defect, see below and ** is "in both the ordinary and tag name spaces" (C11, 7.1.3 Reserved identifiers, 1).

Here we see that C99 (and later) reserves more (if the table is correct). Extra: for what purpose?

Does C99 (and later) 7.1.3 Reserved identifiers miss "external"?

Clearly C99 and each subsequent version of C, up to and including the current latest, C17, omit the qualification "external" in the provision you're asking about. That doesn't necessarily constitute a defect in their text.

So, per C99 (and later), in:

 typedef int _t; // non-reserved in C89, reserved in C99 (and later) static int _f(int x); // non-reserved in C89, reserved in C99 (and later)

(declared at file scope) the _t and _f are reserved, which contradicts with Rationale and with C89.

Yes, those declarations, appearing at file scope, declare _t and _f with no linkage and internal linkage, respectively. They are not external identifiers (though they are declared in external declarations ), and therefore C89 does not reserve them for that use. C99 and later, on the other hand, do reserve them for that use.

"Contradicts" is too strong for this difference. Yes, C99 reserves some identifier usages that C89 does not (and vice versa ). This is not the only backwards incompatibility between the two. C99 "cancels and replaces" C89, so the former is not required to be consistent with all details of the latter.

As for the rationale, yes, it explains the C89 version of the reservations, not the C99 form. I take that to be a flaw in the rationale, which, after all, is not normative.

Does it mean that C99 (and later) misses "external" in 7.1.3 Reserved identifiers: "All external identifiers that..."?

I see no reason to conclude that the omission of "external" from that provision in C99 and later represents an editorial error. In fact, I take corresponding changes in the surrounding text as evidence that the change was intentional. In particular, The C89 text continues with "all other identifiers that begin with an underscore and either an upper-case letter or another underscore" (emphasis added), whereas C99 and later drop the "other" as well. As far as I can see, C99 intended to reserve more identifier uses than C89 did.

But there is a possible defect here in that C89 reserves some identifier uses that C99 does not, but might have intended to do. These are external identifiers at block scope that start with an underscore not immediately followed by a capital letter or another underscore. Example:

int f(void) {
    extern int _var;
    extern int _func(int);

    // ...
}

Those uses of _var and _func are reserved in C89, but not in C99 and later. Conforming C code cannot provide definitions to link to those identifiers, as the identifier reservations in all versions of the spec disallow that, but they could collide with external identifiers defined by the implementation.

I think the rule is the same in both C89 and C99 (ie your example usages are reserved) but the wording has been improved. Paraphrased:

  • Old: "external identifiers [description] are reserved".
  • New: "identifiers [description] are reserved for use in external declarations".

The standard does not even define the term "external identifier"; perhaps this was one of the motivating factors for the wording changing.

If we take "external identifier" to mean "identifier declared by an external declaration", then the rule is the same.


Note: external declaration means "declaration with file scope" (C11 6.9/4); this is often confused with "declaration of identifier with external linkage".

The C89 standard does use the specific text "identifier with external linkage" when that is meant (eg A.6.3.2) so I do not think "external identifier" was supposed to mean "identifier with external linkage".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM