Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different compilation results not using extern in C vs in C++

Tags:

c++

c

extern

When I declare a global variable in two different source files and only define it in one of the source files, I get different results compiling for C++ than for C. See the following example:

main.c

#include <stdio.h>
#include "func.h" // only contains declaration of void print();

int def_var = 10;

int main() {
    printf("%d\n", def_var);
    return 0;
}

func.c

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

/* extern */int def_var; // extern needed for C++ but not for C?

void print() {
    printf("%d\n", def_var);
}

I compile with the following commands:

gcc/g++ -c main.c -o main.o
gcc/g++ -c func.c -o func.o
gcc/g++ main.o func.o -o main

g++/clang++ complain about multiple definition of def_var (this is the behaviour I expected, when not using extern). gcc/clang compile just fine. (using gcc 7.3.1 and clang 5.0)

According to this link:

A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.

So my variable def_var should be defined at the end of each translation unit and then result in multiple definitions (as it is done for C++). Why is that not the case when compiling with gcc/clang?

like image 908
Mike van Dyke Avatar asked Mar 27 '18 11:03

Mike van Dyke


People also ask

Is extern necessary in C?

the extern keyword is used to extend the visibility of variables/functions. Since functions are visible throughout the program by default, the use of extern is not needed in function declarations or definitions.

Is extern default in C?

Use of extern with C functions:- By default, the declaration and definition of a C function have “extern” prepended with them. It means even though we don't use extern with the declaration/definition of C functions, it is present there. For example, when we write. int foo(int arg1, char arg2);

What is the difference between global and extern variable in C?

These variables are defined outside the function. These variables are available globally throughout the function execution. The value of global variables can be modified by the functions. “extern” keyword is used to declare and define the external variables.

When would you be using extern?

The “extern” keyword is used to declare and define the external variables. The keyword [ extern “C” ] is used to declare functions in C++ which is implemented and compiled in C language. It uses C libraries in C++ language.


1 Answers

This isn't valid C either, strictly speaking. Says as much in

6.9 External definitions - p5

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

You have two definitions for an identifier with external linkage. You violate that requirement, the behavior is undefined. The program linking and working is not in opposition to that. It's not required to be diagnosed.

And it's worth noting that C++ is no different in that regard.

[basic.def.odr]/4

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see [class.ctor], [class.dtor] and [class.copy]). An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.

Again, a "shall" requirement, and it says explicitly that no diagnostic is required. As you may have noticed, there's quite a bit more machinery that this paragraph can apply to. So the front ends for GCC and Clang probably need to work harder, and as such are able to diagnose it, despite not being required to.

The program is ill-formed either way.


As M.M pointed out in a comment, the C standard has an informative section that mentions the very extension in zwol's answer.

J.5.11 Multiple external definitions

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).

like image 100
StoryTeller - Unslander Monica Avatar answered Sep 20 '22 12:09

StoryTeller - Unslander Monica