Reputation: 297
Every Google search explains them as just "names for your variables", but I have a feeling there is a distinction between the identifier and the identifier's name. Is an identifier more like an object with attributes like name, scope, linkage, and an underlying object? I ask this because I ran into some trouble trying to read through the C standard. For instance, the snippet
int main(){
int x;
extern int x;
}
fails to compile whereas
int main(){
int x;
if(1){extern int x;}
}
compiles successfully. In this question, the failure of the first snippet is explained from 6.2.2.6 in the C standard, which states that local variables have no linkage. However, in the second snippet, the local variable still has no linkage and yet there is no conflict. Now, 6.2.2.4 states
For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.
My explanation would have been that this rule is in effect in both snippets, but in the first one, the uniqueness of the underlying object of x
triggers a constraint violation via 6.2.1.2 because the same identifier name is being used for two distinct objects with the same scope and name space. But this is not the explanation given in the answer to the question I linked earlier. In the second snippet, the linkage types are still conflicting, so does changing the scope of the extern
declaration change the visibility of the local declaration? What is the best way to think about linkage from the abstract point of view of the C standard (without using actual implementations like gcc or clang as illustration)?
Upvotes: 0
Views: 677
Reputation: 141534
"identifier" is an element of the language grammar. After preprocessing, all tokens are one of the following: keyword, identifier, constant, string-literal or punctuator.
If a token starts with a letter (or underscore) it can only be a keyword or an identifier. If it's not in the table of keywords then it is an identifier. For more technical detail on this , see Annex A of the C Standard.
In your program x
and main
are identifiers, int
, if
and extern
are keywords, 1
is a constant, and everything else is a punctuator.
Identifiers are used as names of entities. The same identifier can be used in different scopes to designate different entities (or the same entity). Linkage is the name of the process by which identifiers are associated with entities.
Sometimes the standard uses the word "identifier" to mean the entity identified by an identifier, this is covered in 6.2.1/5:
Unless explicitly stated otherwise, where this International Standard uses the term “identifier” to refer to some entity (as opposed to the syntactic construct), it refers to the entity in the relevant name space whose declaration is visible at the point the identifier occurs.
The first code is erroneous because of 6.7/3:
If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that: [...]
The int x;
has no linkage so there shall not be another definition of x
in the same scope. (The list of exceptions does not have anything relevant to this case).
In the second code, 6.7/3 is not violated because the second declaration is not in the same scope as the first one. The text you quoted explains that extern int x;
names a different entity than int x;
did, which is fine.
The second program has undefined behaviour (no diagnostic required) due to declaring an identifier with external linkage but not providing a definition. You may or may not see an error message.
Upvotes: 6