Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Tentative definition versus external linkage

Reply
Thread Tools

Tentative definition versus external linkage

 
 
RG (Rafael Giusti)
Guest
Posts: n/a
 
      03-13-2008
I'm having some trouble understanding the rationale for C99 when it
comes to external linkage... The rationale says (Section 6.2.2, near
line 25):

"The Standard model is a combination of features of the strict ref/def
model and the initialization model. As in the strict ref/def model,
only a single translation unit contains the definition of a given
object because many environments cannot effectively or efficiently
support the "distributed definition" inherent in the common or relaxed
ref/def approaches. However, either an initialization, or an
appropriate declaration without storage class specifier (see 6.9),
serves as the external definition. This composite approach was chosen
to accommodate as wide a range of environments and existing
implementations as possible."

What confuses me is the the following assertion: "only a single
translation unit contains the definition of a given object". To help
me illustrate my point, here's a program, which consists of two
translation units:

/* slave.c */
#include <stdio.h>
int external_object;
void print(void)
{
printf("%d\n", external_object);
}

/* main.c */
int external_object;
void print(void);
int main(void)
{
external_object = 8;
print();
return 0;
}

Well, if I compile and run this program, I'll get 8 as output. No
problem so far.

However, if I am to analyze the output of nm for both slave.o and
main.o object files, here's what I get:

main.o:
00000004 C external_object
00000000 T main
U print

slave.o:
00000004 C external_object
00000000 T print
U printf

Now, the ANSI C99 standard says the following about declarations and
definitions (Section 6.7, 5):

A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
-- for an object, causes storage to be reserved for that object;

Well, according to nm, both main.o and slave.o reserve storage for the
object external_object, and should be considered definitions of
external_object. Hence, GCC breaks the standard by allowing more than
one definition of the external_object and then letting the linker
decide that all but one definition of external_object are actually
declarations, just like the relaxed ref/def demands!

Is that possible? What am I missing here?

Thans!
rg
 
Reply With Quote
 
 
 
 
santosh
Guest
Posts: n/a
 
      03-13-2008
RG (Rafael Giusti) wrote:

> I'm having some trouble understanding the rationale for C99 when it
> comes to external linkage... The rationale says (Section 6.2.2, near
> line 25):
>
> "The Standard model is a combination of features of the strict ref/def
> model and the initialization model. As in the strict ref/def model,
> only a single translation unit contains the definition of a given
> object because many environments cannot effectively or efficiently
> support the "distributed definition" inherent in the common or relaxed
> ref/def approaches. However, either an initialization, or an
> appropriate declaration without storage class specifier (see 6.9),
> serves as the external definition. This composite approach was chosen
> to accommodate as wide a range of environments and existing
> implementations as possible."
>
> What confuses me is the the following assertion: "only a single
> translation unit contains the definition of a given object". To help
> me illustrate my point, here's a program, which consists of two
> translation units:
>
> /* slave.c */
> #include <stdio.h>
> int external_object;
> void print(void)
> {
> printf("%d\n", external_object);
> }
>
> /* main.c */
> int external_object;
> void print(void);
> int main(void)
> {
> external_object = 8;
> print();
> return 0;
> }
>
> Well, if I compile and run this program, I'll get 8 as output. No
> problem so far.
>
> However, if I am to analyze the output of nm for both slave.o and
> main.o object files, here's what I get:
>
> main.o:
> 00000004 C external_object
> 00000000 T main
> U print
>
> slave.o:
> 00000004 C external_object
> 00000000 T print
> U printf
>
> Now, the ANSI C99 standard says the following about declarations and
> definitions (Section 6.7, 5):
>
> A declaration specifies the interpretation and attributes of a set of
> identifiers. A definition of an identifier is a declaration for that
> identifier that:
> -- for an object, causes storage to be reserved for that object;
>
> Well, according to nm, both main.o and slave.o reserve storage for the
> object external_object, and should be considered definitions of
> external_object. Hence, GCC breaks the standard by allowing more than
> one definition of the external_object and then letting the linker
> decide that all but one definition of external_object are actually
> declarations, just like the relaxed ref/def demands!
>
> Is that possible? What am I missing here?


The 'external_object' is placed in the so called "common" section of the
object files. During runtime, all references to it are mapped to only
one actual object.

 
Reply With Quote
 
 
 
 
santosh
Guest
Posts: n/a
 
      03-13-2008
santosh wrote:

<snip>

> The 'external_object' is placed in the so called "common" section of
> the object files. During runtime, all references to it are mapped to
> only one actual object.


You can see this if you tell gcc to dump the assembler code generated
for both the source files by using the '-S' command option.

 
Reply With Quote
 
santosh
Guest
Posts: n/a
 
      03-13-2008
santosh wrote:

> santosh wrote:
>
> <snip>
>
>> The 'external_object' is placed in the so called "common" section of
>> the object files. During runtime, all references to it are mapped to
>> only one actual object.

>
> You can see this if you tell gcc to dump the assembler code generated
> for both the source files by using the '-S' command option.


Forgot to add that an 'nm' on the executable file will demonstrate that
there is only one instance of 'external_object'.

 
Reply With Quote
 
santosh
Guest
Posts: n/a
 
      03-13-2008
santosh wrote:

> santosh wrote:
>
> <snip>
>
>> The 'external_object' is placed in the so called "common" section of
>> the object files. During runtime, all references to it are mapped to
>> only one actual object.

>
> You can see this if you tell gcc to dump the assembler code generated
> for both the source files by using the '-S' command option.


Also see this:

<http://www.gnu.org/software/binutils/manual/gas-2.9.1/html_chapter/as_7.html#SEC76>

 
Reply With Quote
 
RG (Rafael Giusti)
Guest
Posts: n/a
 
      03-13-2008
On Mar 13, 12:04 pm, santosh <(E-Mail Removed)> wrote:
> Also see this:
>
> <http://www.gnu.org/software/binutils/manual/gas-2.9.1/html_chapter/as...>


Well, that explains how GCC works, but doesn't seem to explain this:

"As in the strict ref/def model, only a single translation unit
contains the definition of a
given object because many environments cannot effectively or
efficiently support the
"distributed definition" inherent in the common or relaxed ref/def
approaches"

If GCC puts unitialized extern objects that do not include the extern
keyword in the common section, then all declarations/definitions are
equal and all of them reserve storage. So all of them are definitions.
That means GCC follow the relaxed ref/def, not the strict ref/def.
Either that or I'm still missing something very important.

Also, it seems to me that the only way to comply with the strict ref/
def would be requiring that the declaration of global_object in one of
the translation units included the word extern.
 
Reply With Quote
 
Ralf Damaschke
Guest
Posts: n/a
 
      03-13-2008
RG (Rafael Giusti) wrote:

[ using block scope "int external_object;" in two translation
units of a program ]

> Now, the ANSI C99 standard says the following about
> declarations and definitions (Section 6.7, 5):
>
> A declaration specifies the interpretation and attributes of a
> set of identifiers. A definition of an identifier is a
> declaration for that identifier that:
> -- for an object, causes storage to be reserved for that
> object;
>
> Well, according to nm, both main.o and slave.o reserve storage
> for the object external_object, and should be considered
> definitions of external_object. Hence, GCC breaks the standard
> by allowing more than one definition of the external_object
> and then letting the linker decide that all but one definition
> of external_object are actually declarations, just like the
> relaxed ref/def demands!
>
> Is that possible? What am I missing here?


Yes, it is possible; in both translation units the tentative
definition of the object external_object eventually becomes an
external definition with initialization to 0 (6.9.2). Somewhat
above, 6.9 says under "Semantics":

| If an identifier declared with external linkage is used in an
| expression (other than as part of the operand of a sizeof
| operator whose result is an integer constant), somewhere in the
| entire program there shall be exactly one external definition
| for the identifier; otherwise, there shall be no more than one.

This is "shall" requirement outside of a constraint and its
violation leads to undefined behavior and does not need a
diagnostic. Thus the behavior you observed is allowed by the
C standard (I am not sure about POSIX requirements).

Ralf
 
Reply With Quote
 
RG (Rafael Giusti)
Guest
Posts: n/a
 
      03-13-2008
On Mar 13, 12:33*pm, Ralf Damaschke <(E-Mail Removed)> wrote:
> This is "shall" requirement outside of a constraint and its
> violation leads to undefined behavior and does not need a
> diagnostic. Thus the behavior you observed is allowed by the
> C standard (I am not sure about POSIX requirements).


Hmmmm... so is it correct to say that GCC follows the relaxed ref/def
linkage model instead of the Standard linkage model?
 
Reply With Quote
 
Ralf Damaschke
Guest
Posts: n/a
 
      03-13-2008
RG (Rafael Giusti) wrote:

> On Mar 13, 12:33*pm, Ralf Damaschke <(E-Mail Removed)> wrote:
>> This is "shall" requirement outside of a constraint and its
>> violation leads to undefined behavior and does not need a
>> diagnostic. Thus the behavior you observed is allowed by the
>> C standard (I am not sure about POSIX requirements).

>
> Hmmmm... so is it correct to say that GCC follows the relaxed
> ref/def linkage model instead of the Standard linkage model?


Not really. As shown above, here it's the responsibility of the
programmer to follow the strict model, not that of the
implementation. At least you may say that the particular gcc
implementation allows you to use a relaxed (or common? I don't
know whether these are distinct) model in this particular usage.
Whether all gcc versions on all possible platforms do allow that,
well, that would be better asked in gnu.gcc.help.

Ralf
 
Reply With Quote
 
Flash Gordon
Guest
Posts: n/a
 
      03-13-2008
RG (Rafael Giusti) wrote, On 13/03/08 15:19:
> On Mar 13, 12:04 pm, santosh <(E-Mail Removed)> wrote:
>> Also see this:
>>
>> <http://www.gnu.org/software/binutils/manual/gas-2.9.1/html_chapter/as...>

>
> Well, that explains how GCC works, but doesn't seem to explain this:
>
> "As in the strict ref/def model, only a single translation unit
> contains the definition of a
> given object because many environments cannot effectively or
> efficiently support the
> "distributed definition" inherent in the common or relaxed ref/def
> approaches"
>
> If GCC puts unitialized extern objects that do not include the extern
> keyword in the common section, then all declarations/definitions are
> equal and all of them reserve storage. So all of them are definitions.
> That means GCC follow the relaxed ref/def, not the strict ref/def.
> Either that or I'm still missing something very important.


The important thing you are missing is implementations are not required
to diagnose (complain about) all programming errors. Specifically your
code invokes "undefined behaviour" and does not require a diagnostic
(error, warning, informational message, kick in the teeth etc). So gcc
(and the linker) not reporting the problem is not an error in gcc (or
the linker), and because it is undefined behaviour *anything* is allowed
to happen, including the program behaving as you describe.

> Also, it seems to me that the only way to comply with the strict ref/
> def would be requiring that the declaration of global_object in one of
> the translation units included the word extern.


On some systems you can get gcc to compile the code such that the linker
will report an error with your code. Just the gcc documentation (or
search this group) for the switch as I'm too lazy at the moment to find
it myself.
--
Flash Gordon
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Ruby List Roast - A Tentative Attempt Hope Less Ruby 8 08-21-2009 02:15 PM
c++ linkage vs c linkage ramasubramanian.rahul@gmail.com C++ 1 09-12-2008 11:41 AM
Re: Mozilla versus IE versus Opera versus Safari Peter Potamus the Purple Hippo Firefox 0 05-08-2008 12:56 PM
External object definition and linkage J. J. Farrell C Programming 12 04-05-2004 11:40 PM
tentative introduction Dev Lunsford MCSA 8 09-09-2003 02:40 PM



Advertisments