1

Why does GCC allow re-declaration of a 'static' function inside the same translation unit, like so:

static int foo(void);
extern int foo(void)
{
        return 0;
}

when the opposite is not allowed:

extern int foo(void);
static int foo(void)
{
        return 0;
}

The latter fails with a "static declaration of 'foo' follows non-static declaration" error, which I completely understand.

I would expect the same error sort of error for the prior, but that one compiles and links just fine.

zonk
  • 11
  • 1
  • @P.P Note that the dupe is actually quite different. There OP asks for why the second case here is actually allowed, while in this question OP understands that: "*The latter fails with a "static declaration of 'foo' follows non-static declaration" error, which I completely understand.*". This question is about why the first case is valid: "*Why does GCC allow re-declaration of a 'static' function inside the same translation unit, like so:*" – RobertS supports Monica Cellio Jun 30 '20 at 10:41
  • 1
    @RobertSsupportsMonicaCellio Also, the answer there seems more speculative, whereas you cited the Standard :-) – underscore_d Jun 30 '20 at 10:43
  • 3
    @RobertSsupportsMonicaCellio There are many duplicates. Jens' answer explains the important "why" (one is allowed while other isn't). I have now added more dups with "quotes". – P.P Jun 30 '20 at 10:47
  • 2
    @P.P Thank you for your work. Didn't said that Jens' answer isn't relevant, but has quite a little different focus. [What happens when non-static function declaration follows static function declaration?](https://stackoverflow.com/questions/28264874/what-happens-when-non-static-function-declaration-follows-static-function-declar) is the appropriate duplicate (or this question is an appropriate dupe of this question). – RobertS supports Monica Cellio Jun 30 '20 at 11:01
  • I have added a presumed rationale to the best-fitting duplicate: https://stackoverflow.com/a/62656453/3150802 – Peter - Reinstate Monica Jun 30 '20 at 11:31

1 Answers1

4

It is because of this term (emphasize mine) in the C standard:

"For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage."

  1. As specified in 6.2.1, the later declaration might hide the prior declaration.

Source: C18, §6.2.2/4

That means that the first example is valid. The linkage of the function foo is determined by the prior declaration of it, which is internal / static.

The reason for this is probably because of compatibility to function definitions which omit the static qualifier, which are declared as extern by default:

"If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern."

Source: C18, §6.2.2/5

which is also considered in Peter's answer to Rationale of static declaration followed by non-static declaration allowed but not vice versa.

Example:

static int foo (void);

....

int foo (void)          // extern by default.
{
       return 0;
}

Since foo is defined at global scope, its linkage is external by default and with that equivalent to as it have been qualified with extern.

In the second example, you attempt to redeclare a extern/ having external linkage (global scope) as static (file scope) function, which is not permissible.

So, it is not a GCC specific kind of thing, as you thought it would be.

  • I am just trying to understand the reason behind this being allowed, and why would you write something like this anyway. It goes against all regulated industry SW standards I have come across. – zonk Jun 30 '20 at 12:35
  • @RobertSsupportsMonicaCellio I think it makes some sense, as I explain [in my post](https://stackoverflow.com/a/62656453/3150802) (which you have reviewed already, thanks!): Declaring a function static at the top of a file (so that it can be used) and later defining it, omitting the `static`, is a probably not uncommon use case. The opposite though is most likely an error. – Peter - Reinstate Monica Jun 30 '20 at 13:27
  • @Peter-ReinstateMonica Cleaned up thoughts. What I meant was that it doesn't make sense to declare a static function definition as `extern` explicitly, which this whole entire confusion brought up. But since the omission any qualifer is equivalent to `extern` you will be end up to be more right than me. Updated the answer as well. – RobertS supports Monica Cellio Jun 30 '20 at 15:10
  • 1
    Right, I should emphasize that more: *Because* the default is `extern`, making an extra rule for allowing "default extern" (which may be an oversight) but not "explicit extern" (which most likely indicates an error) would require distinguishing the two "externs". As it is, they are being treated alike (which is good). – Peter - Reinstate Monica Jun 30 '20 at 15:22
  • @zonk Updated my answer. Also take a look at Peter's which I have linked. – RobertS supports Monica Cellio Jun 30 '20 at 15:38