when should multiple definitions of global variables trigger link time errors?

Y

yossi.kreinin

Hi!

When are multiple definitions of global variables with the same name
considered legal in C, and how is it different from C++? It appears
that in terms of assembly language, some C definitions are translated
to "weak" symbols, in which case multiple definitions are merged by the
linker, while some become "normal" symbols, triggering linker errors in
case they are defined more then once. Is it true that in C++, multiple
definitions are always disallowed?

This code (2 translation units) compiles with gcc -ansi, but triggers
linker errors with g++:

//weak1.c (or weak1.cpp):
#include <stdio.h>
int a[5];
void f();
int main()
{
printf("&a=%p\n",a);
f();
}

//weak2.c (or weak2.cpp):
#include <stdio.h>
int a[10];
void f()
{
printf("f: &a=%p\n",a);
}

Compiled with gcc, it prints:

&a=0x80495e0
f: &a=0x80495e0

- showing that the definitions `int a[5]' and `int a[10]' were merged.
A symbol table listing shows that the dimension of a[] in the linked
binary is 10. Adding initializers to the definitions, for example,
triggers linker errors in C.

Thanks in advance!
Yossi
 
F

Flash Gordon

Hi!

When are multiple definitions of global variables with the same name
considered legal in C,
Never.

> and how is it different from C++?

Not topical on comp.lang.c, but I would expect it to be the same.
> It appears
that in terms of assembly language, some C definitions are translated
to "weak" symbols, in which case multiple definitions are merged by the
linker, while some become "normal" symbols, triggering linker errors in
case they are defined more then once.

That may be the case on some implementations, but it is not true on all.
On one of the C implementations I use regularly it will produce a link
time error on multiple definitions of a symbol, on another it won't.
That's the wonder of Undefined Behaviour, *anything* can happen.
> Is it true that in C++, multiple
definitions are always disallowed?

This code (2 translation units) compiles with gcc -ansi, but triggers
linker errors with g++:

Use different options with gcc and you may get different results.
//weak1.c (or weak1.cpp):
#include <stdio.h>
int a[5];

//weak2.c (or weak2.cpp):
#include <stdio.h>
int a[10];

<snip>

Undefined behaviour in C. Anything can happen.

binary is 10. Adding initializers to the definitions, for example,
triggers linker errors in C.

So will selecting the correct option in some versions of gcc.
Specifically the -fno-common option. You should also use -pedantic if
you want gcc to be a fully compliant C compiler, and looking at and
enabling the other warnings would also be a good thing.
 
M

Mark McIntyre

Hi!

When are multiple definitions of global variables with the same name
considered legal in C,

Never, there can be only one definition of any object.

Multiple global declarations are fine though, so long as they're the
same. Your example with two different declarations of 'a' should have
triggered a warning from your compiler, and is I believe undefined
behaviour.
and how is it different from C++?

No idea.

Mark McIntyre
 
M

Mark McIntyre

Hi!

When are multiple definitions of global variables with the same name
considered legal in C,


Use different options with gcc and you may get different results.
//weak1.c (or weak1.cpp):
#include <stdio.h>
int a[5];

//weak2.c (or weak2.cpp):
#include <stdio.h>
int a[10];

<snip>

Undefined behaviour in C. Anything can happen.

IIRC these are declarations and tentative definitions. The fact that
they're different is indeed UB but its not illegal to have several
tentative definitions.
Mark McIntyre
 
Y

yossi.kreinin

IIRC these are declarations and tentative definitions. The fact that
they're different is indeed UB but its not illegal to have several
tentative definitions.

Could you please explain that? If I understand correctly, you say that
`int a[5]' in both translation units are "declarations and tentative
definitions", but I don't understand exactly what that means. Does it
mean that multiple definitions are going to be allowed by the compiler,
but the behaviour is only defined when they are identical (if so,
identical on what level)? Which definitions are tentative?

TIA,
Yossi
 
Y

yossi.kreinin

Thanks!

I use -Wall -ansi -pedantic. I assumed it does the trick. Forgive me if
it's the wrong place to ask, but while we're at it - what are the
correct options to ask gcc for it's fullest standard compliance? It
looks like -ansi -pedantic are not enough.

Or is it standard compliant to ignore multiple definitions of a[],
especially if I fixed them to define the same array size? Do any
multiple definitions trigger undefined behaviour, or only different
ones?
 
M

Micah Cowan

Mark McIntyre said:
Hi!

When are multiple definitions of global variables with the same name
considered legal in C,


Use different options with gcc and you may get different results.
//weak1.c (or weak1.cpp):
#include <stdio.h>
int a[5];

//weak2.c (or weak2.cpp):
#include <stdio.h>
int a[10];

<snip>

Undefined behaviour in C. Anything can happen.

IIRC these are declarations and tentative definitions. The fact that
they're different is indeed UB but its not illegal to have several
tentative definitions.

This is only true within the same translation unit. A tentative
definition still causes the object to be defined at the end of the
unit. Since both units define it, this causes UB regardless of
disagreement on type.

-Micah
 
L

lawrence.jones

Could you please explain that? If I understand correctly, you say that
`int a[5]' in both translation units are "declarations and tentative
definitions", but I don't understand exactly what that means.

A tentative definition is a declaration that will be interpreted as a
definition only if no other (non-tentative) definition appears in the
translation unit. In your case, there are no other definitions in the
translation units, so both of the tentative definitions are, in fact,
interpreted as definitions, resulting in multiple definitions for the
same object, which results in undefined behavior. The code is
incorrect, but there's no obligation for the compiler/linker to diagnose
it.

-Larry Jones

I've got an idea for a sit-com called "Father Knows Zilch." -- Calvin
 
M

Mark McIntyre

Could you please explain that? If I understand correctly, you say that
`int a[5]' in both translation units are "declarations and tentative
definitions", but I don't understand exactly what that means.

A tentative definition is a declaration that will be interpreted as a
definition only if no other (non-tentative) definition appears in the
translation unit. [/QUOTE]

Agh, for some reason i had it in my head that the rule was across all
TUs.
Mark McIntyre
 
F

Flash Gordon

Mark said:
(e-mail address removed) wrote:
//weak1.c (or weak1.cpp):
#include <stdio.h>
int a[5];
//weak2.c (or weak2.cpp):
#include <stdio.h>
int a[10];
<snip>

Undefined behaviour in C. Anything can happen.

IIRC these are declarations and tentative definitions. The fact that
they're different is indeed UB but its not illegal to have several
tentative definitions.

No, at the end of each TU the tentative definition becomes an actual
definition if no definition has been found in *that* TU. So each of the
files defines a making it UB even if the definitions are changed to match.

I've stripped comp.lang.c++ from the newsgroups as we both read
comp.lang.c and I only know the C rules.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top