This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/15360] New: c99: extern w/initializer; extern w/internal linkage


Reading specs from /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2.2/specs 
Configured with: ../configure --prefix=/usr --libdir=/usr/lib --with-slibdir=/lib 
--mandir=/usr/share/man --infodir=/usr/share/info --enable-shared 
--enable-threads=posix --disable-checking --enable-long-long 
--enable-__cxa_atexit --enable-languages=c,c++,ada,f77,objc,java 
--host=i586-mandrake-linux-gnu --with-system-zlib 
Thread model: posix 
gcc version 3.2.2 (Mandrake Linux 9.1 3.2.2-3mdk) 
 
 
**************** 
 
 
The following program produces errors/warnings from gcc in -std=c99 mode. 
This, I believe, is incorrect behavior. The gcc tested is version 3.2.2 from a 
Mandrake 9.1 system (glibc 2.2/ kernel 2.4.18xxx/ gcc 3.2.2-3mdk?). 
 
 
program a.in.c: 
 
static int x0; 
extern int x0=8; 
int main() { 
} 
 
[[[ gcc -std=c99 -o a.out a.in.c ]]] 
produces error: 
 
a.in.c:2: warning: `x0' initialized and declared `extern' 
a.in.c:2: conflicting declarations of `x0' 
a.in.c:1: `x0' previously declared here 
 
 
Relevant quotations from the public draft C99 standard I am using (n2794): 
 
6.2.2 Linkages of identifiers: 
[#3] If the declaration of a file scope identifier for an 
 object or a function contains the storage-class specifier 
 static, the identifier has internal linkage.20) 
[#4] For an identifier declared with the storage-class 
 specifier extern in a scope in which a prior declaration of 
 that identifier is visible,21) 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. 
6.9.2 External object definitions 
[#1] If the declaration of an identifier for an object has 
 file scope and an initializer, the declaration is an 
 external definition for the identifier. 
[#2] A declaration of an identifier for an object that has 
 file scope without an initializer, and without a storage- 
 class specifier or with the storage-class specifier static, 
 constitutes a tentative definition. If a translation unit 
 contains one or more tentative definitions for an 
 identifier, and the translation unit contains no external 
 definition for that identifier, then the behavior is exactly 
 as if the translation unit contains a file scope declaration 
 of that identifier, with the composite type as of the end of 
 the translation unit, with an initializer equal to 0. 
[#4] EXAMPLE 1 
 static int i2 = 2; // definition, internal linkage 
 extern int i3 = 3; // definition, external linkage 
 static int i5; // tentative definition, internal linkage 
 int i2; // 6.2.2 renders undefined, linkage disagreement 
 int i3; // valid tentative definition, refers to previous 
 int i5; // 6.2.2 renders undefined, linkage disagreement 
 extern int i2; // refers to previous, whose linkage is internal 
 extern int i3; // refers to previous, whose linkage is external 
 extern int i5; // refers to previous, whose linkage is internal 
>>> See also 6.9 [#4] for more on "external definition" and 6.7.8 for more on 
Initialization, if background is desired.. actually, read the whole thing for proper 
background! 
 
 
Running gcc -std=c99 ... on the above 9 lines of code (but w/ lines 4, 6 
commented out) yields: 
>> a.in.c:2: warning: `i3' initialized and declared `extern' 
Apparantly gcc does not quietly accept initialization on extern declarations. 
 
Also looking back at the 3 messages that gcc produced to the example at the 
top, it seems to me that, in addition to disliking extern with initialization, gcc 
doesn't believe that extern can be used with an identifier that already has 
internal linkage. 
 
So, gcc doesn't believe... 
-- extern can be used with an initialization [at file scope!] 
-- extern can be used to redeclare an identifier with prior internal linkage. 
 
Clearly, if the draft standard is correct, something is wrong when gcc produces 
warnings to the very example that the document says is acceptable. This is for 
the case of extern with initialization at file scope. The reason it is correct (as I 
read it) is simply that nowhere is it prohibited. In general, extern is one of 5 
storage specifiers and these can be used in any "declaration" unless stated 
otherwise. A declaration, as the syntax indicates, can include an initializer 
unless prohibited otherwise. There are numerous exceptions but nowhere that I 
have read does it say that extern and initialization can't go together ever. In 
particular, the example I put up top and the example from the draft standard 
should work (as I read it). 
 
To use some terminology from the document, the first line is a declaration of 
the identifier x0. It declares an object with type int and internal linkage (see 
6.2.2 #3). It's scope is file scope which begins essentially with the semicolon 
that ends the declaration and continues until the end of the translation unit. The 
identifier is not hidden anywhere (in the example). Finally, the declaration is a 
tentative definition (6.9.2 #2): if storage for this object is not otherwise reserved 
by the end of the translation unit, storage, capable of holding an int, will be 
reserved and initialized to 0 at (prior to) program startup. 
 
The second line declares an identifier x0. This is a legal declaration that also 
serves as a definition (storage for an int is reserved and will be initialized to 8 
at program startup) .. the declaration is an external definition (6.9.1 #1) [notice 
also that it is at file scope and not at block scope]. Since this identifier is the 
same as the other one in scope and with linkage, the extern keyword "links" the 
two objects so that they are one and the same (6.2.2 #4). This object has 
internal linkage (acquired with the earlier declaration), meaning, amongst other 
things, that it isn't reachable directly from outside of the translation unit. 
 
In any case, ** extern can be together with initialization, and extern, in this case, 
refers to an identifier that has internal linkage ** . At file scope (or generally, 
when the prior declaration in scope has linkage), there can be numerous 
declarations of the same object. There can be and is only one definition. 
[technically there can be 0 definitions if the object, as is the case here, is not 
accessed.] 
 
Finally, notice how the following rule does not apply (is not violated): 
6.7.8 Initialization 
[#5] If the declaration of an identifier has block scope, 
 and the identifier has external or internal linkage, the 
 declaration shall have no initializer for the identifier. 
 
 
Am I reading things wrongly or leaving crucial information out? I am pretty sure I 
compiled correctly. 
 
 
hozelda@yahoo.com 
 
ps. The section numbers from this draft of the standard may not coincide with 
the final ISO version. 
ps. I can try to explain with more examples if this isn't clear. Personally, I have 
been surprised by a number of things since reading the standard carefully. I 
may be wrong in my interpretation. If I goofed, I hope no one is insulted.

-- 
           Summary: c99: extern w/initializer; extern w/internal linkage
           Product: gcc
           Version: 3.2.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: hozelda at yahoo dot com
                CC: gcc-bugs at gcc dot gnu dot org


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=15360


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]