Let's say that you have a file File1.c with a static function Foo and that the function is called within File1.c. Also, in another file (File2.c), you have another Foo function which is not static. I understand that the static function is not visible outside of the file where it is declared and is actually invisible for the linker.
But does that mean that internal calling of Foo function in File1.c is always resolved during compilation?
Are there cases where Foo calling in File1.c can be linked to the global Foo function of File2.c?
Once you define a static function foo
within a translation unit, foo
refers to that function for the rest of the translation unit, except that it can be hidden by a non-function (such as an object or type definition) named foo
for part of the translation unit. It will not link to an external function named foo
.
By tinkering with declarations as explained below, an identifier could in theory refer to a function from another translation unit after a static
declaration of the same name in this translation unit. Unfortunately, the behavior is not defined by the C standard, due to C 2018 6.2.2 7:
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
That means you cannot rely on the C standard alone to ensure this behavior, but a C implementation could define it as an extension.
These questions are answered by C’s rules for scope and linkage.
Suppose in File1.c
we have a static definition of a function:
static int foo(int x) { return x*x; }
Since the identifier foo
is declared outside of any function, it has file scope (C 2018 6.2.1 4). This means the identifier foo
is visible and designates this function definition for the remainder of File1.c
. Also, since static
was used, it has internal linkage (6.2.2 3).
There is an exception to the scope. For scopes inside other scopes, such as the block { … }
that defines a function inside a file or a block inside a block, a declaration of the same identifier can hide the outer declaration. So let’s consider redeclaring foo
inside a block.
In order to refer to a foo
defined outside of File1.c
, we would need to declare foo
with external linkage, so that this new foo
can be linked to the externally defined foo
. Is there a way to do that in C?
If we try to declare extern int foo(int x);
inside a block, then 6.2.2 4 applies:
For an identifier declared with the storage-class specifier
extern
in a scope in which a prior declaration of that identifier is visible, 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.
So this declaration would merely redeclare the same foo
.
If we declare it without extern
, using int foo(int x);
, 6.2.2 5 applies:
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
.
So, it seems like we cannot declare a different foo with or without extern
. But, wait, we have one more trick. We can make the prior declaration that specifies internal or external linkage invisible by hiding it with a declaration with no linkage. To get a declaration with no linkage, we can declare an object (rather than a function) without extern
:
#include <stdio.h>
static int foo(int x) { return x*x; }
void bar(void)
{
int foo; // Not used except to hide the function foo.
{
extern int foo(int x);
printf("%d\n", foo(3));
}
}
Since, where extern int foo(int x);
appears, the prior declaration of foo
with internal linkage is not visible, that first condition in 6.2.2 4 quoted above does not apply, and the remainder of 6.2.2 4 does:
If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.
This is “legal” C code. Unfortunately, it is undefined by 6.2.2 7:
If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With