0

0.c

int num;
//extern int num; <-- Are these two the same?

int main(){
 return num;
}

1.c

int num; // same as `extern int num;` ?

2.c

int a = 1;

I like to ask 2 questions about the above snippets:

1- This linke says:

A tentative definition is an external declaration without an initializer, and either without a storage-class specifier or with the specifier static.

So based on this, is int num; the same as extern int num; in both 0.c an 1.c?

2- This compiles fine with gcc 0.c 1.c 2.c. I have seen in other posts such as Why can I define a variable twice in C? which explain num is a common symbol. More specifically:

tentative definition becomes a full definition if the end of the translation unit is reached and no definition has appeared with an initializer for the identifier.

So according to this, both int num; in 0.c and 1.c are considered full definitions BUT they are not initialized.

This link says:

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined

So since we have 3 definitions, 2 of which are not initialized then this is considered defined behaviour and safe to use and num will end up being 1?

Dan
  • 2,694
  • 1
  • 6
  • 19
  • It's undefined behaviour and one possible manifestation of UB is for the compiler to accept it with no diagnostic . It seems to me that the question you linked , already fully answers your question, even going into compiler specifics – M.M May 17 '21 at 23:23
  • Except the accepted answer int he link says it is defined behaviour. I have asked a question because every post says a different thing, hence I have adde all the above official documentation to make a conclusion. – Dan May 17 '21 at 23:51
  • Yes, that guy has a bit of an aversion to using the words "undefined behaviour" for some reason. He does correctly say "the C standard does not define the behavior" , but then incorrectly goes on to say that the compiler etc. defines it, and carries on as if the compiler behaviour is somehow defined . – M.M May 18 '21 at 00:41
  • but according to the links I pasted `int num;` is an uninitialized definition in both 0.c and 1.c , which is not listed as UB under the links? if you look at my last reference, it says its only undefined if multiple copies are initialized. – Dan May 18 '21 at 00:59
  • Quoting the accepted answer, "The C standard says “there shall be” at most one definition for an identifier with external linkage (C 2018 6.9 5)". Although actually he did not quote the Standard correctly ; it in fact says that there shall be at most one external definition . (Multiple tentative definitions in the same unit count as a single external definition) – M.M May 18 '21 at 01:01
  • Your last reference is quoting the "Common extensions" appendix – M.M May 18 '21 at 01:03
  • Thanks, I like to confirm the first question with you as well. – Dan May 18 '21 at 01:04
  • `int num;` is not the same as `extern int num;` in any context. The latter is a declaration and the former is a definition. The keyword `extern` is a storage-class-specifier. – M.M May 18 '21 at 01:05
  • But my first link says this :`int i3; // tentative definition, external linkage` – Dan May 18 '21 at 01:10
  • I also want to confirm the UB we discussed holds for external variables. – Dan May 18 '21 at 01:11
  • What do you mean by "external variables"? The description of `i3` is correct – M.M May 18 '21 at 01:13
  • maybe [this thread](https://stackoverflow.com/questions/49511510/) will help, the same answers but worded differently – M.M May 18 '21 at 01:14
  • What I mean is, is my `int num;` external by default even without the `external` keyword added to it? – Dan May 18 '21 at 02:43
  • to answer my question, yes , it's extern, all global variables are extern: https://stackoverflow.com/questions/28610783/are-global-variables-extern-by-default-or-is-it-equivalent-to-declaring-variable – Dan May 18 '21 at 02:48
  • I wanted to confirm this since you said `it in fact says that there shall be at most one external definition `, wanted to confirm the `external` rule applies to me even thought I didn't explicitly mark `num` as extern. – Dan May 18 '21 at 02:59
  • "external definition" has nothing to do with the `extern` keyword, it sounds like you are mixing up two different concepts. "external definition" means definition that's not inside a function (and excludes tentative definitions). "global variable" is not standard terminology – M.M May 18 '21 at 04:08
  • Sine I'm still confused abut this, I created this post: https://stackoverflow.com/questions/67587124/is-having-global-variables-in-common-blocks-an-undefined-behaviour – Dan May 18 '21 at 13:21
  • For question 1, “is `int num;` the same as `extern int num;` in both 0.c [and] 1.c?”: No, `int num;` is a tentative definition, and `extern int num;` is a declaration that is not a definition. – Eric Postpischil May 20 '21 at 23:07
  • For question 2, that link is to an informative part of the standard, not normative. It describes what some C implementations do, not what the standard requires. For compilers that implement this, the behavior is as you describe: Compiling and linking three modules that contain, respectively, `int a;`, `int a;`, and `int a = 1;` will yield one instance of `a` initialized to 1 without an error message. – Eric Postpischil May 20 '21 at 23:10
  • @M.M: I avoid using “undefined” outside the C standard because the standard gives it a specific meaning that is different from its general English sense. Inside the C standard, it means **only** that the standard does not impose any requirements. It does not mean that no documentation defines the behavior. Using the term outside the C standard without qualifying it every time leads to confusion; some people take it to mean the behavior must be undefined in the general sense, which is incorrect. – Eric Postpischil May 20 '21 at 23:17
  • @M.M: Re “incorrectly goes on to say that the compiler etc. defines it”: GCC defines it [here](https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/Code-Gen-Options.html#Code-Gen-Options), under `-fno-common`. (That is the 9.3 version; it is the same in current versions except the default sense of the option changed.) Re “carries on as if the compiler behaviour is somehow defined ”: There is a definition of what the behavior is, so it is defined. – Eric Postpischil May 20 '21 at 23:21
  • @M.M: Re “Although actually he did not quote the Standard correctly”: The words I quoted are “there shall be”, and this text appears exactly as I quoted it at C 2018 6.9 5, second sentence. If you have some gripe with the other text, in which I related the meaning of the standard without quoting it, then say that; do not say I did not quote correctly. As best I can read your complaint, you take my “at most one definition” to count multiple tentative definitions as more than one. However, the standard does not include “tentative definitions” in “definitions,” as can be seen at C 2018 6.9.2 2,… – Eric Postpischil May 20 '21 at 23:30
  • where the passage “If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier…” shows us that you can have tentative definitions without any external definition, so a tentative definition is not an external definition in the meaning of the standard. – Eric Postpischil May 20 '21 at 23:30
  • @EricPostpischil I'm referring to your text "The C standard says “there shall be” at most one definition for an identifier with external linkage (C 2018 6.9 5)." which is not correct as there can be multiple tentative definitions in the same unit . IMO a tentative definition is a definition as per the usual rules of the English language (e.g. a red car is a car). 6.9.2/2 excludes "tentative definition" from "external definition", but not from "definition" – M.M May 21 '21 at 02:02
  • @M.M: As I explained, a *tentative definition* is not an *definition*. The C standard defines *tentative definition* as a term on its own, not an adjective “tentative” modifying “definition,” in C 2018 6.9.2 2. And, as I showed, that definition **excludes** a *definition* (or at least an *external definition*) because otherwise the sentence “If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, …” is nonsensical… – Eric Postpischil May 21 '21 at 02:26
  • … If a tentative definition were an external definition, it would be impossible to contain “one or more tentative definitions” but contain “no external definition.” Your opinion cannot be true because it is inconsistent with the usage in the standard. It is also consistent with the usage at 6.9 5, as 6.9.2 2 indicates multiple tentative definitions may be present but 6.9 5 says that shall be no more than one external definition. Arguing that a tentative definition is a definition as per the usual rules of English fails as we can see from the fact that a vice principal is not a principal. – Eric Postpischil May 21 '21 at 02:33
  • @EricPostpischil maybe you misread my comment. I am claiming a tentative definition IS a definition, and IS NOT an external definition. The inconsistencies you try to raise in your last comments are not actually inconsistences according to my position. – M.M May 21 '21 at 02:40
  • @M.M: That is also inconsistent with the standard. If a tentative declaration were a definition, then it would be “an external declaration that is also a definition of a function (other than an inline definition) or an object” which is the definition of *external definition* in 6.9 5. – Eric Postpischil May 21 '21 at 02:59

0 Answers0