29

For example:

code1.c / .cpp

int a;

// ... and so on

code2.c / .cpp

int a;

int main(void) {
    return 0;
}

go to compile:

$gcc code1.c code2.c      # this is fine
$

$g++ code1.cpp code2.cpp  # this is dead
/tmp/ccLY66HQ.o:(.bss+0x0): multiple definition of `a'
/tmp/ccnIOmPC.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

Is there any global variable linkage difference between C & C++?

Bossliaw
  • 698
  • 1
  • 10
  • 23
  • 3
    You can avoid the issue in C++ by using either `static` or (preferably) a nameless namespace, but that's not your question. I'm not familiar enough with C linkage rules (as opposed to C++) to answer that, I'm afraid. – Sven Jun 16 '11 at 11:32
  • 2
    http://blogs.oracle.com/ali/entry/what_are_tentative_symbols – Sebastian Mach Jun 16 '11 at 11:42
  • Sorry for leaving keyboard for a while, I still new to here and I began to review my asked question... – Bossliaw Jun 16 '11 at 12:48
  • 1
    possible duplicate of [Redefinition allowed in C but not in C++?](http://stackoverflow.com/questions/5337370/redefinition-allowed-in-c-but-not-in-c) – legends2k Mar 03 '14 at 12:02

4 Answers4

22

It's not strictly legal. int a; is a tentative definition in C. You are allowed multiple tentative definitions and at most one non-tentative definition per translation unit of each object with external linkage in C, but only one definition across all translation units in a program.

It is a commonly implemented extension to allow tentative definitions across multiple translation units in C so long as not more than one translation unit contains a non-tentative definition, but it's not strictly standard.

In C++ int a; is just a definition - there's no concept of tentative - and it's still illegal to have multiple definitions of an object across the translation units of a program.

For the C case, you may wish to look at this question.

Community
  • 1
  • 1
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • It's not an extension; it's part of the standard, just like K&R function syntax (i.e: if a compiler doesn't implement it, then it's not compliant). The ANSI standard requires these things to be supported so that pre-C89 codebases can still be compiled with modern compilers. C++ never made such a requirement as it was never intended to be compatible with C to begin with. If it was, it would be weakly typed and the standard would require compilers to also respect the ANSI C standard. – Braden Best May 02 '21 at 21:57
  • Where tentative definitions are mentioned in the standard: ISO/IEC 9899:1999 §6.9 *External definitions* – Braden Best May 02 '21 at 22:11
5

It's illegal in both, but C compilers generally implement an extension. See this answer.

Community
  • 1
  • 1
Artefacto
  • 96,375
  • 17
  • 202
  • 225
  • It's not illegal in C. It's fully legal as per the standard. See ISO/IEC 9899:1999 *§6.9 External definitions* wherein the C99 standard describes tentative definitions. Not an extension. If your compiler doesn't implement it, and claims it's an "unnecessary extension", then the vendor has unwittingly violated the standard. – Braden Best May 02 '21 at 22:09
  • @BradenBest The definitions in `code1.c` and `code2.c` are both tentative definitions, but both become definitions when the end of the each file is reached. Therefore, the variable `a` will be defined in two different translation units. This is the situation "J.5.11 Multiple external definitions" refers to. if the files `code1.c` and `code2.c` were concatenated and compiled as one it would be fine. – Artefacto May 03 '21 at 10:53
  • Makes sense, but if we're purely talking about C, then it's still legal since linking (where it will fail) is up to implementation details. A linker could see the same symbol multiple times and arbitrarily decide to throw one of the definitions away. The compiler itself doesn't care. – Braden Best May 05 '21 at 15:46
  • @BradenBest That is not my understanding of [6.9 paragraph 5](http://port70.net/~nsz/c/c11/n1570.html#6.9p5): _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_ – Artefacto May 05 '21 at 17:06
  • The rule is technically unenforceable because you can just as well compile each module separately and then compile their output together into an executable, where the linker will stop you. To my understanding, once you get into object files, assembly output, and executable/abi-specific stuff, it stops being relevant to C, as the linker doesn't implement C. Character limit hang on. – Braden Best May 06 '21 at 23:22
  • I actually went ahead and tested this with GCC. I made two files: [foo.c](https://pastebin.com/raw/4Rm68CuE) and [main.c](https://pastebin.com/raw/XJVYNdKB), both containing the line `int foo;` in the file-scope space, or "global namespace" if you're so inclined. I compiled the .c files separately with `gcc -c [file].c` and then compiled the .o files together with no complaints from the compiler nor the linker. The program runs without issue, producing the expected value of 0. Seems either GCC isn't adhering to the standard or we've had a misunderstanding regarding *tentative definitions* :) – Braden Best May 06 '21 at 23:26
  • I also tried it with g++. In both cases the files by themselves will compile to object files. The difference is in the linkage stage, where the objects generated by gcc will create an executable without issue, while the objects created by g++ will throw a linker error. This is because of tentative definitions, not because of any language extension that I'm aware of. Thoughts? – Braden Best May 06 '21 at 23:33
  • @BradenBest What happens is if you don't explicitly initialize `foo` (and don't use `extern`/`static`), gcc (but not g++, which behaves as if you wrote `int foo = 0;`) marks it as "common" variable (`COM` in the `Ndx` column of readelf) and doesn't allocate space for it in `.bss`; it's then up to the linker to merge the symbols and allocate space in `.data` or `.bss`. This is how they implement the extension I mention in my answer. – Artefacto May 10 '21 at 13:56
  • @BradenBest I guess you could in a way say it's "because" `foo` is a tentative definition, but I find that misleading. This is not a behavior the standard prescribes for tentative definitions. And you still get this behavior of merging symbols if you have a non-tentative definition. Say 1.c `int foo; int main() {return foo;}` and 2.c with `int foo = 2;` will exit with code 2. This is not a strictly conforming program, though. – Artefacto May 10 '21 at 14:05
3

There are three ways for resolution of problem:

  1. If variable a is the same in both files, you must declare it as extern in all files except one. extern keyword says to linker that this name is located in another files.

  2. You may use static keyword to limit scope of variable to one file. In which it is declared.

  3. Or you may use nameless namespace.

George Gaál
  • 1,216
  • 10
  • 21
1

g++ compiler is more strict then gcc compiler. It also depends on version of gcc, may be higher version of gcc i.e. 4.X onwards it can give same error.

Use extern to avoid

Stuti
  • 1,620
  • 1
  • 16
  • 33
  • Both compilers are equally strict. They implement different standards with different rules. Saying C++ is more strict than ANSI C is like saying French is more strict than English: Possibly correct in some circumstances, but at the end of the day you're comparing apples and oranges – Braden Best May 02 '21 at 22:14