[comp.std.c] A question about tenative definitions

rfg@lupine.ncd.com (Ron Guilmette) (03/04/91)

I'm having a discussion with a C implementor I know about the meaning of
the following sentence from the ANSI C standard.  (I think that this came
from section 3.7.2, but I'm at home right now and I don't have the standard
with me at the moment, so I'm not sure.)

	    "If a translation unit contains one or more tenative 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 a composite type as of the end of the translation
	    unit, with an initializer equal to zero."

What exactly does this mean?  My off-the-cuff interpretation of this
statement was that if you had two files like:

	one.c:
	---------------------------------------------------------------------
	int xxyyzz;
	---------------------------------------------------------------------

	two.c:
	---------------------------------------------------------------------
	int xxyyz;
	---------------------------------------------------------------------

and if you compiled them both and then tried to link them together into
the same single program, that you should get an error at link time because
there are two conflicting external *definitions* of the variable xxyyzz.

This implementor I know disagrees with my interpretation.

Who is right? 

debra@wsinfo11.info.win.tue.nl (Paul de Bra) (03/05/91)

In article <4218@lupine.NCD.COM> rfg@lupine.ncd.com (Ron Guilmette) writes:
>I'm having a discussion with a C implementor I know about the meaning of
>the following sentence from the ANSI C standard...
>[ description of tentative definition deleted ]
>What exactly does this mean?  My off-the-cuff interpretation of this
>statement was that if you had two files like:
>... [ example deleted ]
>and if you compiled them both and then tried to link them together into
>the same single program, that you should get an error at link time because
>there are two conflicting external *definitions* of the variable xxyyzz.

Nope, you are wrong.
int xxyyzz; int xxyyzz; int xxyyzz;
may be repeated as often as you like, as they are "tentative" definitions.
you may have several (non-conflicting) tentative definitions of the same
variable.
A true (non-tentative) definition is one with initialization.
you may write int xxyyzz=1; only once.
if none of the (tentative) definitions has an initializer then the
variable will be initialized with 0.

Paul.
(debra@win.tue.nl, debra@research.att.com)

rfg@NCD.COM (Ron Guilmette) (03/05/91)

In article <1807@svin02.info.win.tue.nl> debra@info.win.tue.nl writes:
+In article <4218@lupine.NCD.COM> rfg@lupine.ncd.com (Ron Guilmette) writes:
+>I'm having a discussion with a C implementor I know about the meaning of
+>the following sentence from the ANSI C standard...
+>[ description of tentative definition deleted ]
+>What exactly does this mean?  My off-the-cuff interpretation of this
+>statement was that if you had two files like:
+>... [ example deleted ]
+>and if you compiled them both and then tried to link them together into
+>the same single program, that you should get an error at link time because
+>there are two conflicting external *definitions* of the variable xxyyzz.
+
+Nope, you are wrong.
+int xxyyzz; int xxyyzz; int xxyyzz;
+may be repeated as often as you like, as they are "tentative" definitions.
+you may have several (non-conflicting) tentative definitions of the same
+variable.
+A true (non-tentative) definition is one with initialization.
+you may write int xxyyzz=1; only once.
+if none of the (tentative) definitions has an initializer then the
+variable will be initialized with 0.

Paul, I think that you missed my point entirely.  I know that you are
right that I can put:

	int xxyyzz; int xxyyzz; int xxyyzz;

as many times as I like in ONE COMPILATION UNIT, but look again at the
exact wording from 3.7.2:

	If a translation unit contains one or more tenative 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 an initializer equal to zero.

Now that suggests to me that the following two "translation units" should
be treated (by the compiler and assembler and linker) as being EXACTLY
identical to one another:

	version1.c:
	--------------------------------------------------------------------
	int xxyyz;
	int xxyyz;
	int xxyyz;
	--------------------------------------------------------------------

	version2.c:
	--------------------------------------------------------------------
	int xxyyz = 0;
	--------------------------------------------------------------------

Now if that is true, i.e. if the two translation units about are supposed
to be treated EXACTLY alike, then when I link together the following two
translation units:

	one.c:
	-------------------------------------------------------------------
	int xxyyz;
	int xxyyz;
	int xxyyz;
	-------------------------------------------------------------------
	two.c:
	-------------------------------------------------------------------
	int xxyyz;
	int xxyyz;
	int xxyyz;
	-------------------------------------------------------------------

I should get EXACTLY the same number and types of errors (no more and
no less) as I would get when I tried to like together the following two
translation units:

	three.c:
	-------------------------------------------------------------------
	int xxyyz = 0;
	-------------------------------------------------------------------
	four.c:
	-------------------------------------------------------------------
	int xxyyz = 0;
	-------------------------------------------------------------------

Now I'm willing to conceed that this may not have been what x3j11 intended,
however that *is* the way 3.7.2 reads.

You are suggesting that the true meaning of 3.7.2 is that if there is a
whole set of tenative definitions for some symbol within a given set of
linker input files, that the linker is supposed to create one (and only
one) zero initializer for the whole set.

I know that this is the way that things were traditionally done, but I
certainly *don't* yet know if that was the intent of x3j11.

I wish that somebody who was on x3j11 would tell me if that was the
committee's intent or not.

If it *was* the intent of x3j11 to do things in the traditional manner,
I think that they should have worded 3.7.2  so that that would have been
more clear.

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// New motto:  If it ain't broke, try using a bigger hammer.

sarima@tdatirv.UUCP (Stanley Friesen) (03/06/91)

In article <4218@lupine.NCD.COM> rfg@lupine.ncd.com (Ron Guilmette) writes:
>I'm having a discussion with a C implementor I know about the meaning of
>the following sentence from the ANSI C standard. 
 
>	    "If a translation unit contains one or more tenative 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 a composite type as of the end of the translation
>	    unit, with an initializer equal to zero."
>
>What exactly does this mean? ...

< Example consisting of two translation units (=files) deleted>

>... if you compiled them both and then tried to link them together into
>the same single program, that you should get an error at link time because
>there are two conflicting external *definitions* of the variable xxyyzz.
>
>This implementor I know disagrees with my interpretation.
>
>Who is right? 

In essence you are right.  The example you gave generates what ANSI calls
'undefined behavior'.  This means that it is *not* a conforming C program.

It also, generally, means that *any* behavior on the part of the system is
acceptable.  So, this *may* mean that the implementor's approach is a legal
local *extension* to ANSI C.  Of course any programs that depend on such an
extension will not be portable.  [It is a legal extension as long as the
ANSI standard does not *require* a diagnostic for this error; I do not
believe it does, so the extension is likely to be legal].

The whole matter is discussed in some detail in the rationale document.
-- 
---------------
uunet!tdatirv!sarima				(Stanley Friesen)

gwyn@smoke.brl.mil (Doug Gwyn) (03/11/91)

In article <4228@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes:
>If it *was* the intent of x3j11 to do things in the traditional manner,
>I think that they should have worded 3.7.2  so that that would have been
>more clear.

"Tentative definition" is inherently a kludgy notion.
However, it is irrelevant to the actual issue, which was whether
or not a "relaxed ref/def" model could be used for external linkage
by a conforming implementation.  The answer is, yes, it is permitted,
because programs that exploit this conforming extension do not have
to violate a syntax rule or constraint to do so.  However, such
programs are definitely not strictly conforming programs.