4

--- a.c ----

int i; // external definition

---- main.c ------

int i=0; // external definition 

int main(void)
{
i=0;
}

In both files i is an external defnition in each translation unit and i is used in an expression. That should violate:

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.140)

Sabrina
  • 1,460
  • 11
  • 23
  • 1
    How are you compiling this? – Fantastic Mr Fox Feb 14 '17 at 00:02
  • 1
    `int i;` in `a.c` is a *tentative definition*. See [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 6.9.2p2. – Keith Thompson Feb 14 '17 at 00:05
  • I am using `gcc -Wall -g` – Sabrina Feb 14 '17 at 00:05
  • 1
    This is technically an extension but it is very, very common. The linker merges both `a.c` and `main.c`'s definitions of `i`. If you change `a.c` to read `int i = 1;` you should then get an error. – zwol Feb 14 '17 at 00:05
  • @KeithThompson I read 6.9.2p2 as saying that `int i;` at file scope is equivalent to `int i=0;` at file scope if no other initializers for that variable appear in the _translation unit_. That doesn't address Sabrina's concern which is about multiple translation units? – zwol Feb 14 '17 at 00:07
  • Is a tentative definition considered as external definition ? – Sabrina Feb 14 '17 at 00:23
  • Read about 'Not so good way to define global variables' in [How do I use `extern` to share variables between source files in C](https://stackoverflow.com/questions/1433204). It is not strictly compatible with standard C, but the C standard itself recognizes it as a common extension — and there's a pun involved in the use of 'common' because it occurs on many systems (one meaning of common), and it also mimics the behaviour of Fortran COMMON blocks (another meaning of common). The relevant section of the standard is §6.9.2 External object definitions. – Jonathan Leffler Feb 14 '17 at 00:38
  • You still not answer the question: can a tentative definition be considered as external definition ? – Sabrina Feb 14 '17 at 00:42
  • @Sabrina You can understand it from the text. A tentative definition is not an external definition. It's actually not a definition at all (it's a declaration). – anatolyg Feb 14 '17 at 00:50
  • @anatolyg: False. According to your logic this program is then invalid: `int i; int main() { i = 42; }` since it does not contain a definition of `i`. In reality, as stated in the standard, a tentative defintion becomes a regular definition at the end of translation unit. So, while `int i;` is a *tentative definition* it produces a normal definition at the end of `a.c`. That definition will clash with the definition in `main.c`. – AnT stands with Russia Feb 14 '17 at 02:23
  • @Sabrina: All tentative definitions for the same object are combined and converted into a single external definition at the end of the translation unit. – AnT stands with Russia Feb 14 '17 at 02:27
  • Very similar question: http://stackoverflow.com/questions/41606858/why-gcc-compiles-and-links-two-files-even-if-extern-is-not-used/ – M.M Feb 14 '17 at 03:02
  • Yeah I may agree on similarity but answer is not convincing. Answering this is the key: `is a tentative definition considered as external definition` ? @M.M – Sabrina Feb 14 '17 at 03:42
  • @Sabrina: Answering "no" to that question would render the following code invalid: `int i; int main() { i = 42; }`. Yet we all know that this is a perfectly valid program. If `int i;` did not produce an external definition for `i`, then how could it possibly be valid? – AnT stands with Russia Feb 14 '17 at 04:01
  • @Sabrina AnT's answer on this thread explains that point – M.M Feb 14 '17 at 04:07
  • @AnTstandswithRussia I'm confused with "... otherwise, there shall be no more than one". I interpret the whole quote as `ext_def_cnt == 1 || ext_def_cnt <= 1`, which is redundant. Can you comment on that? – pmor Jan 24 '23 at 14:41

1 Answers1

2

This non-standard behavior is a common extension implemented in many C compilers.

This matter is discussed rather extensively in Rationale to C99 standard (see pp. 32-34). And, according to that document, this set of definitions would be legal under Relaxed Ref/Def model typically implemented in UNIX OS's C compilers of pre-C89 era. This is the reason for its popularity and this is why we often see it implemented as an extension. It is supposed to simplify support of legacy code.

Nevertheless, standard C definition model is different: it is a combination of Strict Ref/Def model and Initialization model. Standard C does not allow this.

P.S. While it is true that definition of i in a.c is a tentative definition, it has nothing to do with the issue. By the end of the containing translation unit all tentative definitions of some object combine and give birth to an external definition of the object. Their "tentative" nature is not in any way visible at inter-module level. Tentative definitions do not allow one to create multiple definitions of the same object in different translation units.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765