This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c/15360] New: c99: extern w/initializer; extern w/internal linkage
- From: "hozelda at yahoo dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 10 May 2004 00:26:38 -0000
- Subject: [Bug c/15360] New: c99: extern w/initializer; extern w/internal linkage
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
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