2

If I say

int i=8;

outside of every function, is this definition of a global variable tentative and why?

EDIT: I changed 'conditional' to tentative, I translated it wrong.

Nebeski
  • 610
  • 4
  • 14

2 Answers2

2

If you declare the variable outside of a function scope, then it has static storage duration and by default external linkage. It means that the variable is accessible everywhere in the current translation unit (i.e. the current C file produced by the pre-processor). The variable is also accessible in other translation units, but you need to either declare it there as extern int i; or tentatively define it as int i;. Note that if you define the variable as static int i = 8; at file scope, then the variable will have internal linkage and you won't be able to use it in other translation units, even if declaring there as extern int i;.

There is no conditional going on here, I don't know what you mean by this word.

EDIT

No, yours is not a tentative definition.

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 1
    Wrong: "If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage." (6.2.2p4). – too honest for this site Feb 09 '16 at 21:52
  • 1
    That's not quite right on extern. Unless you explicitly declare it to be `static` within your translation unit, then the linker will allow *any other* translation unit to access it via an `extern` declaration. Also, since this guy is clearly a beginner: "translation unit" = ".c file" in very general terms. – Brian McFarland Feb 09 '16 at 21:52
  • @BrianMcFarland: To be more precise: A translation unit is each ".c"-file passed to the compiler plus all `#include`d files - directly or indirectly. – too honest for this site Feb 09 '16 at 21:54
  • I think vsoftco is using the term `static` in a different sense than the C keyword. It is being used in its broader, non-C-specific sense of storage duration, not scope. – Tom Karzes Feb 09 '16 at 21:54
  • @M.M I was talking about the static storage duration, at global scope, see the link. – vsoftco Feb 09 '16 at 21:54
  • @Olaf which part of this answer is wrong? There was no mention of linkage. – M.M Feb 09 '16 at 21:55
  • @M.M Ohh I see. I will try to clarify it. – vsoftco Feb 09 '16 at 21:57
  • The semi-informal term "global variable" usually refers to objects with external linkage (and, naturally, static storage duration). File scope objects declared with `static` are not typically referred to as "global". – AnT stands with Russia Feb 09 '16 at 21:58
  • If the answer is wrong, please let me know exactly where and why. – vsoftco Feb 09 '16 at 22:02
  • The statement "By default it is visible only in the current translation unit." is just flat out incorrect. Globals you declare w/o `static` can be accessed by *any* code linked against yours unless you make them "file scoped", i.e. static linkage. – Brian McFarland Feb 09 '16 at 22:03
  • 1
    @BrianMcFarland How would you access it without using `extern` in the second translation unit? Also I edited the answer before your comment. If there is something wrong with it now, let me know. – vsoftco Feb 09 '16 at 22:06
  • 1
    @BrianMcFarland Also, there is no static linkage. There is internal linkage, external linkage and no linkage. However, for the scope of this answer, I don't think OP benefits more if we go deep into standardese, that's why I didn't mention anything about linkage (except when you use `static int i = 8;`, which makes the linkage internal). – vsoftco Feb 09 '16 at 22:13
  • Clearly, you do need `extern` in the second translation unit. But declaring a symbol as `extern` is not what gives it external linkage. That's the default mode of operation. You must use `static` to prevent that. You got me on static vs internal for linkage terminology. But I think its a very important distinction that C programmers should learn early. Liberal use of the `static` keyword, both on functions and variables, makes C *way* easier to read, debug, maintain, etc and way too many professional C programmers never use it. – Brian McFarland Feb 09 '16 at 22:18
  • @TomKarzes: The term "static" is correctly used, like in the standard. There is a difference between the `static` storage class specifier and static variables (vs. e.g. automatic). – too honest for this site Feb 09 '16 at 22:20
  • @vsoftco: You don't need to use `extern` to reference a variable in another CU. A tentative definition without final definition is actually enough. – too honest for this site Feb 09 '16 at 22:21
  • @Olaf Thanks, edited, forgot about this (used too much with C++). – vsoftco Feb 09 '16 at 22:23
  • @M.M: I think Brian explianed the problem well enough ("The statement "By default it is visible only ..."). – too honest for this site Feb 09 '16 at 22:24
  • I don't think OP will benefit from using non-standard terms or oversimplifications. Better use them and explain. However, he better use a C book to learn such vital concepts. – too honest for this site Feb 09 '16 at 22:26
  • Removed the DV. Still, I don't see any benefit from differentiating between `extern int i;` and `int i;`. Note also the latter is a _declaration_ which is also a _tentative **definition**_. As there is no other declaration or final definition until the end of the CU, it is "demoted" to a definition for the final code. (I also have to read the standard for all this formal stuff - too deep into the woods). – too honest for this site Feb 09 '16 at 22:31
  • Not sure, but is C++ not quite similar with that? – too honest for this site Feb 09 '16 at 22:34
  • @Olaf, I edited the answer and used all gory details regarding linkage ;) C++ has no tentative definitions, you need `extern`. – vsoftco Feb 09 '16 at 22:35
  • @Olaf `extern int i;` is not a definition at all, it's quite different to `int i;` – M.M Feb 09 '16 at 22:35
  • @M.M: Where did I state `extern int i;` is a _definition? They are not that different here actually, as both are declararations in the first place. But only the latter is also a tentative definition (I think I already stated that). You just cannot have a definition with `extern`. – too honest for this site Feb 09 '16 at 22:40
  • @Olaf Not sure about C, but in C++ you can have a definition with `extern`, namely for `const` variables, which by default [have internal linkage in `C++` (not the case for C)](http://stackoverflow.com/questions/998425/why-does-const-imply-internal-linkage-in-c-when-it-doesnt-in-c). So if you want to change the linkage, you do `extern const int i = 42;`. – vsoftco Feb 09 '16 at 22:45
  • @vsoftco: About `const`: That is one of the differences between the two languages anyway, as they are true constants. C does not have such a concept. But thanks for the update. I actually did not thnik much about the formal background, just use it. – too honest for this site Feb 09 '16 at 22:52
2

If you define a global variable as you have illustrated, then any function that is defined before that variable will not be aware of the variable unless some declaration has been made before the function, or within the function.

void foo () {
    extern int i; /* declare presence of global i */
    /* code that uses i */
}

int i=8;

void bar () {
    /* code that uses i, does not need declaration */
}

A tentative definition for a global is a bare declaration without an initializer.

int i; /* tentative definition */

void foo () {
    /* code that uses i */
}

The tentative definition allows i to be used like in a forward declaration, however, it will also be treated as a default initialized external definition unless an explicit external definition for i is found.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • If you would like some gory details, you can view [this answer](http://stackoverflow.com/a/17800382/315052). – jxh Feb 09 '16 at 22:26
  • The description of tentative definition isn't right; it doesn't "match" a different translation unit. If there is `int i = 5;` in another unit then it is undefined behaviour due to multiple definitions. (your link describes this in more detail) – M.M Feb 09 '16 at 22:36
  • @M.M: I was working from memory on how things worked. But yes, I described that technicality in my linked post. – jxh Feb 09 '16 at 22:42
  • Your last paragraph is really completely different to how tentative definitions work. It doesn't behave as if there were a default initializer, external declarations don't make any difference (unless they provide an initializer), and it does not hint of definitions in another TU (which would be UB). It always creates a definition at the end if no definition with initializer was given in the current TU. – M.M Feb 09 '16 at 22:47
  • @M.M: `int a;` bare has no initializer. If an instance is created, is it not default initialized? If `extern int a;` follows `int a;` does it not treat the tentative as another external declaration? Aren't external declarations hints that definitions are elsewhere? – jxh Feb 09 '16 at 22:57
  • `int a; extern int a;` is identical to `int a;` . External declarations are not necessarily hints that definitions are elsewhere. (`static int x = 5;` is an external declaration - don't mix up "external declaration" with "external linkage"). `int i;` is not default-initialized yet, there may later be `int i = 5;` for example. The difference is more pronounced in the case of a type that is not completed until later (e.g. `int a[];` differs from `int a[] = { 0 };` in that it is incomplete) – M.M Feb 09 '16 at 23:02