Search code examples
cdeclarationstorage-class-specifier

Global variable in header file without extern


Using global variable in header file we can change value/use variable in another file(same value can access/modify in multiple files), then why extern can be used ? What is difference between global and extern ?

Below is the example that i have tried It doesnt make difference between extern and global variable in c.

Program compile and run successfully without any error.

t.h

int i;

t1.c

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

int main()
{
        i=10;
        printf("%s i = %d\n",__func__, i);
        t2();
        printf("%s i = %d\n",__func__, i);
        i=200;
        printf("%s i = %d\n",__func__, i);
        t3();
        printf("%s i = %d\n",__func__, i);

return 0;
}

t2.c

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

void t2()
{
        printf("%s i=%d\n",__func__, i);
        i = 100;
        printf("%s i=%d\n",__func__, i);
}

t3.c

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

void t3()
{
        printf("%s i=%d\n",__func__, i);
        i = 300;
        printf("%s i=%d\n",__func__, i);
}

Output :- gcc t1.c t2.c t3.c

main i = 10
t2 i=10
t2 i=100
main i = 100
main i = 200
t3 i=200
t3 i=300
main i = 300

Solution

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

    So that's what you have: a tentative definition.

    Try different variations in file t.h

    int i;
    int i = 42;
    static int i;
    static int i = 42;
    extern int i;
    

    The description of the various options at gcc documentation may be of help

    -fno-common

    In C code, this option controls the placement of global variables defined without an initializer, known as tentative definitions in the C standard. Tentative definitions are distinct from declarations of a variable with the extern keyword, which do not allocate storage.

    Unix C compilers have traditionally allocated storage for uninitialized global variables in a common block. This allows the linker to resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references.

    The -fno-common option specifies that the compiler should instead place uninitialized global variables in the BSS section of the object file. This inhibits the merging of tentative definitions by the linker so you get a multiple-definition error if the same variable is defined in more than one compilation unit. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable definitions this way.