variable global and macro #ifdef

M

Mug

i have quite curious problem on global variable on C++
suppose we have 3 files
-------------test.h----------------
#ifndef TEST_H
#define TEST_H
#include <stdio.h>

int a;
void whatever();

#endif

--------------------test.c --------------------
#include "test.h"

void whatever()
{
a=10;
printf("la la %d \n",a);
}

-----------------main.c-------------
#include "test.h"
int main()
{
a=9;
whatever();
return 0;
}

those files compile perfect with gcc,
with help of macro #ifndef
but with g++,it give me the mutiple defintion error on variable a.
i have to declare "a" as static to make it work.
so i have conclusion that the macro #ifndef dosen't works.
do someone can tell me why #ifndef doesn't work,and is there some
remedy for the problem?
Mug
 
J

Juha Nieminen

Mug said:
-------------test.h----------------
#ifndef TEST_H
#define TEST_H
#include <stdio.h>

int a;
void whatever();

#endif
those files compile perfect with gcc,
with help of macro #ifndef
but with g++,it give me the mutiple defintion error on variable a.
i have to declare "a" as static to make it work.

No, you have to make it 'extern' to make it work. You are defining the
same global variable in more than one compilation unit, which causes a
collision at the linking stage.

This has nothing to do with the #ifdef.
 
M

Mug

  No, you have to make it 'extern' to make it work. You are defining the
same global variable in more than one compilation unit, which causes a
collision at the linking stage.

  This has nothing to do with the #ifdef.

sure if i declare " a " in main.c and add extern int a in test.h,it
works,
but it was not what i meant, i need to declare the global variable in
a seperated file,NOT in main.
and i am quite persuaded that the problem is from #ifndef, with gcc
the same files compiled and work, because with #ifndef there is just
one compilation unit was include the test.h , that's why there are no
compilation error. (maybe i am wrong, otherwise pls indicate
why with gcc,there were no such problems,and pls give a solution
without the direct decleration in main.c) thanks
 
M

Mug

sure if i declare " a  " in main.c and add extern int a in test.h,it
works,
but it was not what i meant, i need to declare the global variable in
a seperated file,NOT in main.
and i am quite persuaded that the problem is from #ifndef, with gcc
the same files compiled and work, because with #ifndef there is just
one compilation unit was include the test.h , that's why there are no
compilation error. (maybe i am wrong, otherwise pls indicate
why with gcc,there were no such problems,and pls give a solution
without the direct decleration in main.c) thanks

folow my previous post,
with gcc do :
gcc -c test.c
and
gcc -c main.c
it product two object file main.o and test.o
lets see the symbole table with nm command:
zsh/3 3676 % nm test.o
00000004 C a
U printf
00000000 T whatever
and then
zsh/3 3678 % nm main.o
00000004 C a
00000000 T main
U whatever
so we see here the symbole a is note with 00000004 C
it means:
"C" The symbol is common. Common symbols are uninitialized data.
When linking, multiple common symbols may appear with
the same
name. If the symbol is defined anywhere, the common
symbols
are treated as undefined references.
---man nm

with those two object file we can product a executable
with either gcc or g++ without errors

then let's see what happen with g++;
i did g++ -c test.c and g++ -c main.c
then with nm see what happened in symbole table:
surprise:

zsh/3 3681 % nm test.o
00000000 T _Z8whateverv
U __gxx_personality_v0
00000000 B a
U printf
and
zsh/3 3683 % nm main.o
U _Z8whateverv
U __gxx_personality_v0
00000000 B a
00000000 T main

here we see "a" is note with 00000000 B
it means :
"B"
The symbol is in the uninitialized data section (known as BSS ).
--- from man nm

with those two object file,we can NOT have a executable,
i think it may show my point of view,why i think the problem is from
#ifndef
best regard
 
J

Joshua Maurice

sure if i declare " a  " in main.c and add extern int a in test.h,it
works,
but it was not what i meant, i need to declare the global variable in
a seperated file,NOT in main.
and i am quite persuaded that the problem is from #ifndef, with gcc
the same files compiled and work, because with #ifndef there is just
one compilation unit was include the test.h , that's why there are no
compilation error. (maybe i am wrong, otherwise pls indicate
why with gcc,there were no such problems,and pls give a solution
without the direct decleration in main.c) thanks

Just because it happens to work sometimes on some compilers does not
mean it's supposed to work or that it's guaranteed to work by the
standard. The standard clearly requires that each global be defined in
exactly one translation unit. If you put the variable definition "int
a;" in a header and include that header in two different translation
units, you're breaking the One Definition Rule and the results are
undefined, that it, it may work on some compilers and it may not.

Solution: Define the global in exactly one translation unit, be that
main.c or another source file.

Also, it may be working with gcc because ?? gcc assumes a .c file is a
C source file (correct me if I'm wrong), and the C language rules for
what is a definition is different from C++ and its One Definition Rule
is slightly different as well. I \think\ your code is valid C code,
but don't quote me.
 
V

Victor Bazarov

That's how C++ language works. It's different from the C language.
sure if i declare " a " in main.c

What language are you programming in? I strongly recommend sticking to
one language exclusively, unless you have a compelling reason not to (do
you?)
> and add extern int a in test.h,it
works,
but it was not what i meant, i need to declare the global variable in
a seperated file,NOT in main.

You mean, "define", not "declare", the global variable in a separate
file? So do it, what's stopping you?
and i am quite persuaded that the problem is from #ifndef,

Well, it *isn't*.
> with gcc
the same files compiled and work, because with #ifndef there is just
one compilation unit was include the test.h , that's why there are no
compilation error. (maybe i am wrong, otherwise pls indicate
why with gcc,there were no such problems,and pls give a solution
without the direct decleration in main.c) thanks

The difference is in how languages treat declarations of variables
outside of any function. In C the statement

int a;

in the file scope, is not a definition but a "tentative" definition. In
C++ there is no "tentative", it's just a definition. Have the same
statement in more than one translation unit, and C linker will combine
them all to make a single object. The C++ linker, however, will see the
violation of the ODR.

In order to make your code the same in C and C++ (more or less), you
need to (a) declare your object 'extern' in the header:

extern int a; // declaration

and (b) define it in one of the translation units, BUT ONLY IN ONE, like so:

int a(0); // definition

V
 
P

Pascal J. Bourguignon

Mug said:
sure if i declare " a " in main.c and add extern int a in test.h,it
works,
but it was not what i meant, i need to declare the global variable in
a seperated file, NOT in main.

Then do that! Why aren't you doing what you need to do?



-------------a.h----------------------
#ifndef a_h
#define a_h
extern int a;
#endif
-------------a.c----------------------
#include "a.h"
int a=0;
-------------test.h-------------------
#ifndef TEST_H
#define TEST_H
#include <stdio.h>

void whatever();

#endif
--------------------test.c ------------
#include "test.h"
#include "a.h"

void whatever()
{
a=10;
printf("la la %d \n",a);
}
-----------------main.c----------------
#include "test.h"
#include "a.h"

int main()
{
a=9;
whatever();
return 0;
}
----------------------------------------


and i am quite persuaded that the problem is from #ifndef,

No, it is not.
 
J

James Kanze

i have quite curious problem on global variable on C++ suppose
we have 3 files
-------------test.h----------------
#ifndef TEST_H
#define TEST_H
#include <stdio.h>
int a;
void whatever();
#endif
--------------------test.c --------------------
#include "test.h"
void whatever()
{
a=10;
printf("la la %d \n",a);

}
-----------------main.c-------------
#include "test.h"
int main()
{
a=9;
whatever();
return 0;

}
those files compile perfect with gcc, with help of macro
#ifndef but with g++,it give me the mutiple defintion error on
variable a.

First, when you say "those files compile perfect with gcc", I
presume you mean just test.c and main.c (or did you use some
special option so that gcc would consider test.h as a C source,
and compiler it).
i have to declare "a" as static to make it work.

Or do it correctly, and declare a extern in the header, and
define it somewhere.
so i have conclusion that the macro #ifndef dosen't works. do
someone can tell me why #ifndef doesn't work,and is there some
remedy for the problem?

It has nothing to do with the #ifdef. You've defined a twice,
once in each translation unit, which is undefined behavior. For
various historical reasons, most C compilers (including gcc)
treat such definitions much as they would a named common in
Fortran, but most C++ compilers (including g++) generate code
such that the linker detects the error. (There is the anomaly
that g++, for some strange reason, compiles even C sources as
C++.)

But whatever---it's undefined behavior in both languages, so you
shouldn't do it. (I've used C compilers in the past where your
example wouldn't work. And it works as C++ with Sun CC today.
Undefined behavior is just that---undefined.)
 
J

James Kanze

No, you have to make it 'extern' to make it work.
[/QUOTE]

With g++:). Without the extern, it's undefined behavior (both
in C and in C++), and some compilers (e.g. Sun CC) do "make it
work" (for some definition of "make it work"---in my book, the
best thing a compiler can do in cases of undefined behavior like
thisis to generate an error).
sure if i declare " a " in main.c and add extern int a in
test.h,it works, but it was not what i meant, i need to
declare the global variable in a seperated file,NOT in main.

You need to declare the global variable in every translation
unit in which it is used; this is what the extern is for. You
need to define it in one, and exactly one, translation unit:
whether main.c, test.c or some additional source file, it
doesn't matter.
and i am quite persuaded that the problem is from #ifndef,

You're wrong.
with gcc the same files compiled and work, because with
#ifndef there is just one compilation unit was include the
test.h, that's why there are no compilation error.

No. The difference is that for historical reasons, gcc treats
global definitions in C differently than in C++. Multiple
global definitions are undefined behavior in both languages, and
different compilers treat them differently.

And the #ifdef doesn't have any effect accross translation
boundaries.
(maybe i am wrong, otherwise pls indicate why with gcc,there
were no such problems,and pls give a solution without the
direct decleration in main.c)

Put the definition in test.c. Or in some separate file that you
also link into the final executable.
 
J

James Kanze

On Aug 24, 12:39 pm, Mug <[email protected]> wrote:

[...]
Also, it may be working with gcc because ?? gcc assumes a .c
file is a C source file (correct me if I'm wrong), and the C
language rules for what is a definition is different from C++
and its One Definition Rule is slightly different as well.

It's certainly formulated very differently, but I think that the
net effect is the same---undefined behavior. Historically,
however, many pre-standard C compilers (including the one in the
early versions of Unix) treated uninitialized definitions like a
Fortran named common.

(BTW: his filenames all ended with .c, so presumably, are C
code, and should be compiled as C, and not C++.)
I \think\ your code is valid C code, but don't quote me.

I don't think so, but it is frequent C code, so most C compilers
don't want to break it.
 
J

James Kanze

That's how C++ language works. It's different from the C language.

Not in this case.
The difference is in how languages treat declarations of
variables outside of any function. In C the statement
in the file scope, is not a definition but a "tentative"
definition.

But it becomes an "external definition" at the end of the
translation unit, if there are no other definitions.

Where this makes a difference is if you write something like:

int a ;
// ...
static int a ;
// or int a = 42 ;

In C, this is legal---the tentative definition is replaced by
the definitive definition. In C++, it isn't---you have two
conflicting definitions for the same object. However, in C, if
at the end of the translation unit, there are only tentative
declarations, the compiler automatically adds a:
int a = 0 ;
to the code.
In C++ there is no "tentative", it's just a definition. Have
the same statement in more than one translation unit, and C
linker will combine them all to make a single object. The C++
linker, however, will see the violation of the ODR.
In order to make your code the same in C and C++ (more or
less), you need to (a) declare your object 'extern' in the
header:
extern int a; // declaration
and (b) define it in one of the translation units, BUT ONLY IN
ONE, like so:
int a(0); // definition

Technically, you don't need the initializer in either language.
Practically, I find it preferable---if I know that the object is
going to be initialized with 0, why shouldn't I tell the reader.

And of course, if for some reason you want the code to be
compilable as both C and C++, then you should use copy
initialization:
int a = 0 ;
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top