eyal@echo.canberra.edu.au (Eyal Lebedinsky) (02/06/91)
G'day I have a situation where two static structures at the external level are defined and initialized to each have a member pointer to the other. My problem is finding the proper ANSI declarations/definitions for this case. It is obvious that the second object defined should first have a forward declaration for the first object to be properly initialized. Maybe a sketch will do here: <linkage> struct x i7; static struct x i6 = { &i7 }; <linkage> struct x i7 = { &i6 }; Now, the <linkage> is what I find different compilers have different expectations of. ANSI 3.7.2 is where I looked for the answer. I tried gnu (1.39) which I hope is ANSI by now. It likes this one: (1) extern int i7; (2) static int i7 = 1; It hates this one: static int i7; /* tentative definition, internal linkage */ (3) extern int i7 = 1; Microsoft 5.1 likes both, but I wouldn't trust it much. Q: what should the comment on the right say for (1,2,3) in the sense on the examples at the end of 3.7.2? What I want is to first give a 'tentative definition' or a 'declaration' followed later by the initialized 'definition'. I know how shady this area is with traditional compilers and do not wish to discuss it, so please limit replies to ANSI issues.
sarima@tdatirv.UUCP (Stanley Friesen) (02/07/91)
In article <eyal.665840220@echo> eyal@echo.canberra.edu.au (Eyal Lebedinsky) writes: >I tried gnu (1.39) which I hope is ANSI by now. It likes this one: > >(1) extern int i7; >(2) static int i7 = 1; Well, then it is wrong. (1) is a tentative definition with *external* linkage. As such it is incompatible with (2), which is illegal in the same scope. [(1) is external by 3.1.2.2 paragraph 4, the incompatibility is required by paragraph 7]. >It hates this one: > > static int i7; /* tentative definition, internal linkage */ >(3) extern int i7 = 1; Beep, Gnu is wrong again! This is actually the correct way to do it. (3) could also be: static int i7 = 1; The original (3) is legal due to the statement that makes (1) external. In essence, if an 'extern' appears *after* a 'static' it is a backwards reference to the 'static' declaration, otherwise it is an external declaration. The prior declaration is clearly a tentative definition of a variable with internal linakage by 3.7.2 paragraph 2. The examples in 3.7.2 actually support this treatment if read carefully. >Microsoft 5.1 likes both, but I wouldn't trust it much. Well, at least it is only half wrong. It is *required* to diagnose (2) if it follows (1). >Q: what should the comment on the right say for (1,2,3) in the sense on >the examples at the end of 3.7.2? (1) /* tentative definition, external linkage */ (2) /* undefined - linkage disagreement, would be internal linkage */ (3) /* definition, refers to previous (internal linkage) */ Sigh, well, I guess gcc isn't as ANSI as it likes to claim. -- --------------- uunet!tdatirv!sarima (Stanley Friesen)
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (02/07/91)
Say struct foo's first element points to struct bar, and vice versa. Here's how to initialize mutually referencing static structures: static struct { struct foo f; struct bar b; } x = { { &x.b }, { &x.f } }; Done. Most compilers will use fixed addresses for &x.b and &x.f, so this will be just as efficient as separate static structure declarations. In article <eyal.665840220@echo> eyal@echo.canberra.edu.au (Eyal Lebedinsky) writes: > It is obvious that the second object defined should first have a > forward declaration for the first object to be properly initialized. No need. > I know how shady this area is with traditional compilers and do not wish to > discuss it, so please limit replies to ANSI issues. No, the solution above works fine under any C compiler. This is the fourth time since September that the same question has come up in comp.lang.c (and now comp.std.c); my fingers are getting tired. Anyone else think this belongs in the comp.lang.c FAQ? Steve, are you listening? ---Dan
eyal@echo.canberra.edu.au (Eyal Lebedinsky) (02/07/91)
In <14327:Feb622:47:1391@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >Say struct foo's first element points to struct bar, and vice versa. >Here's how to initialize mutually referencing static structures: > static struct { > struct foo f; > struct bar b; > } x = { > { &x.b }, > { &x.f } > }; >Done. Most compilers will use fixed addresses for &x.b and &x.f, so this >will be just as efficient as separate static structure declarations. > [stuff deleted] Yes, this would work. It is a practical solution and I may do it. But I STILL want to know how to do it STRAIGHT, as ANSI intended. After all, this is comp.std.c, not comp.lang.c. >---Dan
mkahl@world.std.com (Michael Kahl) (02/07/91)
In article <131@tdatirv.UUCP> sarima@tdatirv.UUCP (Stanley Friesen) writes: >In article <eyal.665840220@echo> eyal@echo.canberra.edu.au (Eyal Lebedinsky) writes: >>I tried gnu (1.39) which I hope is ANSI by now. It likes this one: >> >>(1) extern int i7; >>(2) static int i7 = 1; > >Well, then it is wrong. (1) is a tentative definition with *external* linkage. >As such it is incompatible with (2), which is illegal in the same scope. >[(1) is external by 3.1.2.2 paragraph 4, the incompatibility is required >by paragraph 7]. Exactly right... except: it's not really "illegal". Paragraph 7 says "if, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined." Undefined, not illegal. Therefore, this construct should be avoided in portable programs, but gcc is perfectly within its rights to accept the usage. >>It hates this one: >> >> static int i7; /* tentative definition, internal linkage */ >>(3) extern int i7 = 1; > >Beep, Gnu is wrong again! This is actually the correct way to do it. Right. An ANSI compiler should accept this. >>Microsoft 5.1 likes both, but I wouldn't trust it much. > >Well, at least it is only half wrong. It is *required* to diagnose (2) >if it follows (1). Wrong. The behavior is undefined. This is neither a constraint violation nor a syntax violation, and so no diagnosis is required. IMHO, allowing an "extern" forward declaration followed later by a definition of the identifier as "static" is a reasonable extension to the language. In some pre-ANSI compilers, this was the *only* way to forward-declare a name not meant to be exported. In deference to existing code, it is reasonable to accept this usage. The Standard permits this extension by leaving the behavior undefined. I don't know this for a fact, but I like to think that it was for this very reason that the committee left it undefined rather than requiring a diagnosis. Neither did they did not mandate this treatment, presumably so as not to place undue burden on compilers that need to address variables differently depending on their linkage, and don't read the entire source file before starting to generate code. -- Michael Kahl, Symantec Corporation mkahl@world.std.com -or- 75236.3146@compuserve.com Disclaimer: Keep this quiet; what my employer doesn't know won't get me fired.
thorinn@diku.dk (Lars Henrik Mathiesen) (02/09/91)
sarima@tdatirv.UUCP (Stanley Friesen) writes: >In article <eyal.665840220@echo> eyal@echo.canberra.edu.au (Eyal Lebedinsky) writes: >>I tried gnu (1.39) which I hope is ANSI by now. It likes this one: >> >>(1) extern int i7; >>(2) static int i7 = 1; >Well, then it is wrong. (1) is a tentative definition with *external* linkage. Actually, (1) is _not_ a definition, just a declaration. If (2) wasn't there, i7 would be reference to a definition in another file. (1) still makes the linkage external since (2) isn't visible at that point.