6

why does this work within global scope:

static int a;
static int a=0;

but not within function's body:

void foo()
{
    static int b;
    static int b=0; //error: Duplicate declaration of global variable 'b'
    ...

using clion 2017.3.1, C99, gcc5.4

lurker
  • 56,987
  • 9
  • 69
  • 103
John
  • 130
  • 1
  • 8
  • 1
    @EugeneSh., *et al*. I don't think this is a duplicate of the cited question. The cited candidate duplicate question doesn't address the inconsistency between static variables declared/defined within a function versus those declared/defined outside of the functions. – lurker Jan 15 '18 at 19:01
  • I think the question itself is addressing it: *A tentative definition is any external data declaration that **has no storage class specifier and no initializer**.* – Eugene Sh. Jan 15 '18 at 19:05
  • @EugeneSh. yes I see what you mean. I think it partially answers the question, or at least is not explicit enough for the OP's scenario. – lurker Jan 15 '18 at 19:28
  • @EugeneSh. this wording is unfortunate as a file scope declaration with the storage class specifier static also constitutes a tentative definition. Better to use the definition from C: *"A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition."* – ouah Jan 15 '18 at 19:46

2 Answers2

3

The first one, in global scope, is an example for a so called Tentative definition.

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

A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.

In the second example, b has block scope and no linkage, in other words: the declarations are not external. Hence, the tentative definition rule does not apply.

Community
  • 1
  • 1
sergej
  • 17,147
  • 6
  • 52
  • 89
  • *In the second example you are in function scope.* It's block scope not function scope. Block scope and function scope are two of the four kinds of scopes. – ouah Jan 15 '18 at 19:34
  • @ouah Right, thanks. – sergej Jan 15 '18 at 19:59
  • "If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration." Is there a sensible scenario to repeat an external definition? – John Jan 17 '18 at 14:22
1

In the first code snippet, you have what C calls a tentative definition and an external definition:

(C11, 6.9.2p2) "A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. [...]"

In the second code snippet, you are not at file scope but at block scope and it's why it is not allowed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ouah
  • 142,963
  • 15
  • 272
  • 331
  • @coderredoc only the first declaration in the file scope code snippet constitutes a tentative definition. As there is an external definition right after, the tentative definition is treated here as a referencing declaration. – ouah Jan 15 '18 at 20:21
  • What rule is there that says an external definition and tentative def can co-exist? 6.9.2 doesn't. That's why without even saying them I approached the answer from different point. – user2736738 Jan 15 '18 at 20:31
  • @coderredoc My understanding is that there is no rule that disallows it. The tentative definition becomes a definition of the object only in absence of the external definition (as per 6.9.2p2), so it's not a definition here in the sense it does not reserve storage for that object. But it serves as a declaration for the identifier (still as per 6.9.2p2) and, as you quoted it from 6.7p3, multiple declarations of an identifier with compatible types at the same scope are only explicitly disallowed when the identifier has no linkage. – ouah Jan 15 '18 at 21:42
  • @coderredoc Note that the (non-normative) example of 6.9.2p4 shows an external definition and a tentative definition (`i1` identifier). – ouah Jan 15 '18 at 21:56
  • First comment is the as per rule. Though the second example doesn't break the same(via example). That is why I directly said the standard parts regarding declaration which applies here. But yes, second is ext def (*file sope and an initialzer*) and first is tent def. (suprisingly all this could be explained differently too). – user2736738 Jan 16 '18 at 03:26