Search code examples
cdeclarationdefinitionextern

Trying to understand extern in C


By the answer given here, I am trying to construct a working example and try to understand behavior of the extern linkage.

Here is my example:

extern.h

extern int global_counter;

int file_counter;

extern.c

#include "extern.h"

int global_counter = 5;

incrementor1.c

#include "extern.h"
#include <stdio.h>

void incrementor1_global()
{
    global_counter++;
    printf("From Incrementor1...\n");
    printf("Global counter is: %d\n", global_counter);
}

void incrementor1_local()
{
    file_counter++;
    printf("From Incrementor1...\n");
    printf("File counter is: %d\n", file_counter);
}

incrementor2.c

#include "extern.h"
#include <stdio.h>

void incrementor2_global()
{
    global_counter++;
    printf("From Incrementor2...\n");
    printf("Global counter is: %d\n", global_counter);
}

void incrementor2_local()
{
    file_counter++;
    printf("From Incrementor2...\n");
    printf("File counter is: %d\n", file_counter);
}

You can yourself put these into separate files as depicted. Here is my main.c now:

main.c

void incrementor1_global();
void incrementor1_local();

void incrementor2_global();
void incrementor2_local();

int main(char argc, char* argv[])
{
    incrementor1_global();
    incrementor2_global();

    incrementor1_local();
    incrementor2_local();
}

Since I link .o files to my main, I am just declaring the functions and since they are extern by default, they are linked by the linker as I understood. And lastly, here is a makefile if you want to try it yourself.

CC=gcc

CFLAGS=-I.

DEPS = extern.h

OBJ = main.o extern.o incrementor1.o incrementor2.o  

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

main: $(OBJ)
    gcc -o $@ $^ $(CFLAGS)


.PHONY: clean

clean:
    rm -f *.o  

So by the answer linked above, I think global_counter should be shared by all translation units while each should have their own copy of file_counter. But the output I get is:

From Incrementor1...
Global counter is: 6
From Incrementor2...
Global counter is: 7
From Incrementor1...
File counter is: 1
From Incrementor2...
File counter is: 2

So, I think both incrementor have a one copy of file_counter and that is a global variable. But now I don't know how I can replicate the answer given and make them have their own copy. Any suggestions?

By the way, If I want to give a definition to file_counter in extern.h, since it is included in both incrementors I am getting multiple definitions error. This confuses me further on how could I make them have a shared copy.


Solution

  • int file_counter is a tentative definition and is a global variable (with external linkage), as it is defined outside of any function. It is a good practice to have variable definitions in C source files, not in headers.

    If you want each translation unit to have its own copy of file_counter, one way is to mark it as static and define it both in incrementor1.c and incrementor2.c. In that case, the visibility of the variable will be restricted only to the file in which it is defined.