Author Topic: linkage in c  (Read 4160 times)

0 Members and 1 Guest are viewing this topic.

Offline BlogRahulTopic starter

  • Regular Contributor
  • *
  • Posts: 75
  • Country: in
linkage in c
« on: December 11, 2021, 10:10:16 am »
I'm trying to understand what is the role of the linker in my code. What is internal and external linkage?

Here is my code that conatians multiple files

shared.h
Code: [Select]
extern int x;
void foo();

 foo.c
Code: [Select]

int x;
void foo() {
  x++;
}

main.c
Code: [Select]
#include <stdio.h>
#include "shared.h"

int main() {
  x = 37;
  printf("%d\n", x);
  foo();
  printf("%d\n", x);

  return 0;
}
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6785
  • Country: pl
Re: linkage in c
« Reply #1 on: December 11, 2021, 10:53:04 am »
Compiler is what turns source code files into object files (foo.o, main.o on UNIX or .obj on Windows).
Linker is what puts those object files together into the final executable.
(Some compilers support going from C files straight to executable, they run the linker automatically behind your back).
Linking permits code in one file (main) to refer to functions and variables from other files (foo).

The extern keyword appears in main.c when shared.h is included into it and it instructs the compiler not to create the x variable in main.o but to reference a yet-nonexistent external variable and leave it to the linker to stitch things together.

Meanwhile in foo.o, an actual integer variable is created.

This is analogous to "void foo() {...}" versus "void foo();" - one creates a function, the other enables calling a function created elsewhere. It should probably also have extern in it for logical consistency, but C syntax never made much sense ::)
 
The following users thanked this post: BlogRahul

Offline BlogRahulTopic starter

  • Regular Contributor
  • *
  • Posts: 75
  • Country: in
Re: linkage in c
« Reply #2 on: December 11, 2021, 02:35:13 pm »
Compiler is what turns source code files into object files (foo.o, main.o on UNIX or .obj on Windows).
Linker is what puts those object files together into the final executable.
(Some compilers support going from C files straight to executable, they run the linker automatically behind your back).
Linking permits code in one file (main) to refer to functions and variables from other files (foo).

The extern keyword appears in main.c when shared.h is included into it and it instructs the compiler not to create the x variable in main.o but to reference a yet-nonexistent external variable and leave it to the linker to stitch things together.

Meanwhile in foo.o, an actual integer variable is created.

This is analogous to "void foo() {...}" versus "void foo();" - one creates a function, the other enables calling a function created elsewhere. It should probably also have extern in it for logical consistency, but C syntax never made much sense ::)
@magic Thanks  I am working with GCC compiler on PC

There are three types of linkage: external linkage, internal linkage, and no linkage.

What changes have to made in the uploaded code if want to check these three types of errors?
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: linkage in c
« Reply #3 on: December 12, 2021, 04:48:57 pm »
What changes have to made in the uploaded code if want to check these three types of errors?
The (correct) terms you are using are the ones in the standard.
For the standard 'linkage' means (very very simply) 'the behaviour when an identifier is declared more then once in a different or the same  scope'.
This is a bit different, but has of course a strict relationship with what a linker does: putting together compiled translation units (~= source files) and making sure that identifier names correspond to the right object (the relevant part is underlined).

The definition of the three linkage type are (summarizing from the C11 standard, Ch 6.2.2):
  • All the declaration of an identifier with internal linkage represent the same object or function in the same translation unit.
  • All the declaration of an identifier with external linkage represent the same object or function across all the same translation units.
  • All the declaration of an identifier with no linkage represent the same entity.
Note the shift of language between internal/external and no linkage: entity is used instead of object or function, as also typedef names, struct tags, function parameters etc. are identifiers with no linkage.

Now, all of this is nice, formally sound and consistent, but some complications (and confusion) are brought by the fact that in C linkage is signified by the keywords extern and static (or their absence) that have other semantics related to the storage duration (= time of life) or by where a declaration is found.

Ojects or functions declared with "static" will have internal linkage.

Objects or functions declared with "extern" will have external linkage, if no previous declaration is found.

Objects at file scope, and functions, default to extern.
Objects at block scope default to no linkage.

Example file A:
Code: [Select]
static int i; /* i has internal linkage */
extern int i; /* Fine, i is still static - compiler will not complain - as the previous declaration takes priority */

File B:
Code: [Select]
extern int i; /* This is i is not the same as the one above, as that one has internal linkage! */
Other example:
Code: [Select]
extern int i; /* no previous declaration, i has external linkage */
static int i; /* loud complaining from the compiler: static means internal linkage, but the object has external linkage! */
Note the difference with file A above!

No linkage:
Code: [Select]
void f(int i); /* i has no linkage */

void f(int i)
{
  int j; /* Also j ha no linkage */
  extern int k; /* but k has external linkage */
  static int n; /* and n has internal linkage */
}
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: BlogRahul

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #4 on: December 14, 2021, 01:08:38 am »
  • All the declaration of an identifier with no linkage represent the same entity.

Well, that's a bit misleading. The language standard explicitly states that "Each declaration of an identifier with no linkage denotes a unique entity." This is completely different from what you stated above.

In fact, it is impossible to produce multiple declarations of the same entity with no linkage: any attempts to do so would represent constraint violations, i.e. they would be flagged as errors.

No linkage:
Code: [Select]
void f(int i); /* i has no linkage */

void f(int i)
{
  int j; /* Also j ha no linkage */
  extern int k; /* but k has external linkage */
  static int n; /* and n has internal linkage */
}

This is also incorrect. `n` has no linkage. Even though it is declared with `static`, local `static` declarations produce entities with no linkage (!).
« Last Edit: December 14, 2021, 01:11:10 am by TheCalligrapher »
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6785
  • Country: pl
Re: linkage in c
« Reply #5 on: December 14, 2021, 06:36:31 am »
Not sure about k too.
I tried similar code and an extern local variable is accepted and does appear in the symbol table, but differently from a global and it can't be linked against by normal means.
I guess one would have to dig into standards/manuals to understand what happens here :-//
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #6 on: December 14, 2021, 06:56:25 am »
Not sure about k too.
I tried similar code and an extern local variable is accepted and does appear in the symbol table, but differently from a global and it can't be linked against by normal means.
I guess one would have to dig into standards/manuals to understand what happens here :-//

I don't see anything difficult about `k`. The above `k` is a non-defining declaration. It is not a definition. You can't "link against it" since there's nothing to link against.
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6785
  • Country: pl
Re: linkage in c
« Reply #7 on: December 14, 2021, 07:52:26 am »
 :palm:
Right, it's a way of pulling external globals into the local scope.
I didn't even realize it's a thing.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4040
  • Country: nz
Re: linkage in c
« Reply #8 on: December 14, 2021, 09:32:57 am »
Not sure about k too.
I tried similar code and an extern local variable is accepted and does appear in the symbol table, but differently from a global and it can't be linked against by normal means.
I guess one would have to dig into standards/manuals to understand what happens here :-//

Code: [Select]
#include <stdio.h>

int k;

void foo(){
  int k = 42;
  printf("k = %d at start of foo\n", k);
  {
    extern int k;
    ++k;
    printf("k = %d in middle of foo\n", k);
  }
  printf("k = %d at end of foo\n", k);
}

int main(){
  k = 100;
  printf("k = %d at start of main\n", k);
  foo();
  printf("k = %d at end of main\n", k);
  return 0;
}

When run ...

Code: [Select]
k = 100 at start of main
k = 42 at start of foo
k = 101 in middle of foo
k = 42 at end of foo
k = 101 at end of main

It gives access to whatever k is at global scope in the program (not necessarily the same source file)
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: linkage in c
« Reply #9 on: December 14, 2021, 09:39:40 am »
Well, that's a bit misleading.
Nope - it's completely and utterly wrong  :bullshit:, as you later correctly point out.
I plead death by copy-paste, though that does not excuse me, I should have re-read.
Each entity with no linkage is unique.

This is also incorrect. `n` has no linkage. Even though it is declared with `static`, local `static` declarations produce entities with no linkage (!).
In re-reading §3 and §6 of 6.2.2, I think you are right here too. This was a real misunderstanding on my side (I though it resolved to the expected behaviour due to the scope, rather than linkage).

I always appreciate your well reasoned and documented posts, so:
Thanks al lot for your corrections, TheCalligrapher!  :clap:
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #10 on: December 14, 2021, 03:47:15 pm »
It gives access to whatever k is at global scope in the program (not necessarily the same source file)

It is true, but the underlying mechanism is a bit more elaborate. As newbrain stated above, this is legal

Code: [Select]
/* `k` is not declared yet */
static int k;
extern int k;

The `extern` declaration "inherits" internal linkage from the previous declaration of `k`.

`extern` actually performs a name lookup and tries to find a prior declaration of the same identifier, as stated in 6.2.2/4. And, per 6.2.2/4

  • 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.

Point 1 is what makes the above example with "inherited" linkage work.

Point 2 states that in this (reversed order) example

Code: [Select]
/* `k` is not declared yet */
extern int k;
static int k;

the first declaration declares `k` with external linkage and the second one declares it with internal linkage. This is undefined behavior per 6.2.2/7, but most С compilers will immediately flag it as an "error".

Finally, we can concoct the following more elaborate (and strange) example

Code: [Select]
static int k; /* 1 */

int main(void)
{
  int k; /* 2 */
 
  {
    extern int k; /* 3 */
  }
}

In this case the declaration #3 finds the previous declaration #2. Since the declaration #2 has no linkage, declaration #3 declares `k` with external linkage (per 6.2.2/4 above). And, according to 6.2.2/7 the behavior is undefined: declaration #3 conflicts with the declaration #1.

The point I'm making here is that declaration #2 is not ignored by #3. It plays its role in the whole process. Declaration #2 hides declaration #1 from declaration #3, which is what ultimately makes this example undefined. If we comment out declaration #2, this behavior will become defined: #3 will refer to #1 and "inherit" internal linkage from #1.

It is interesting to note that GCC flags this as an error as well: http://coliru.stacked-crooked.com/a/e701023e51333227
Meanwhile Clang is quiet about it: http://coliru.stacked-crooked.com/a/4569f4092ad26c06
Clang has no trouble flagging the more trivial example of the same UB: http://coliru.stacked-crooked.com/a/fb5a86047cf262ba
« Last Edit: December 14, 2021, 06:58:51 pm by TheCalligrapher »
 
The following users thanked this post: newbrain

Online magic

  • Super Contributor
  • ***
  • Posts: 6785
  • Country: pl
Re: linkage in c
« Reply #11 on: December 14, 2021, 05:39:06 pm »
Those rules are very bizarre.
Is there any situation where using extern as anything other than "forward declaration" actually makes sense?
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #12 on: December 14, 2021, 06:52:27 pm »
Is there any situation where using extern as anything other than "forward declaration" actually makes sense?

In "classic" C (C89/90) non-redundant uses of `extern` boil down to:

1. "Forward declaration" of a variable.
2. Unhiding a file-level variable hidden by a local variable, as shown in the examples above (this is rare).

In modern C (C99 and later) you have one more use:

3. Combination `extern inline` emits external definition for an inline function.

---

In C++ there's one more prominent use of `extern`: overriding default internal linkage for `const` objects

Code: [Select]
extern const int k = 42;
The above `k` would have internal linkage (since `const` implies internal linkage in C++), but thanks to the explicit `extern` it receives external linkage in this declaration.
« Last Edit: December 14, 2021, 06:59:33 pm by TheCalligrapher »
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6785
  • Country: pl
Re: linkage in c
« Reply #13 on: December 14, 2021, 09:36:25 pm »
Well, you omitted the third possibility of importing global objects from other TUs into an individual block scope.

I'm just not quite sure who would want to use that block-scope extern for any reason IRL and how it ended up in the standard.
I have never seen such thing and I'm pretty sure it wouldn't pass code review in most places. Just rename the variables if they clash.
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #14 on: December 14, 2021, 09:49:08 pm »
Well, you omitted the third possibility of importing global objects from other TUs into an individual block scope.

I assumed this to be covered by "forward declaration". I understand "forward declaration" as a declaration that basically says that "the definition is located elsewhere", not necessarily in this very translation unit. Where this declaration is made - in block scope or in file scope - makes no tangible difference.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14490
  • Country: fr
Re: linkage in c
« Reply #15 on: December 14, 2021, 10:25:39 pm »
I'm just not quite sure who would want to use that block-scope extern for any reason IRL and how it ended up in the standard.
I have never seen such thing and I'm pretty sure it wouldn't pass code review in most places. Just rename the variables if they clash.

This is more than absolutely HORRIBLE. It's a doubly pathological case of variable shadowing.

How it ended up in the standard? No clue, but a couple hypotheses. The main one I have in mind is that it might have been allowed, *not necessarily willingly*, by older C compilers, and the committee had to keep that feature for legacy reasons. (This is very common throughout the standard.)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: linkage in c
« Reply #16 on: December 15, 2021, 03:02:05 am »
Quote
I'm trying to understand what is the role of the linker in my code. What is internal and external linkage?
I'm a little worried because it seems that handling C's "linkage" concepts seems to be only a very small part of what "the linker" does.
(in fact, for functions with "internal (static) linkage", the linker might not be involved at all.)
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: linkage in c
« Reply #17 on: December 15, 2021, 03:24:05 am »
(in fact, for functions with "internal (static) linkage", the linker might not be involved at all.)

That's the intent. In a typical С implementation internal linkage is handled entirely by the compiler proper. Linker knows nothing about it.
« Last Edit: December 15, 2021, 03:26:36 am by TheCalligrapher »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf