variable global and macro #ifdef

Discussion in 'C++' started by Mug, Aug 24, 2009.

  1. Mug

    Mug Guest

    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
     
    Mug, Aug 24, 2009
    #1
    1. Advertising

  2. Mug wrote:
    > -------------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.
     
    Juha Nieminen, Aug 24, 2009
    #2
    1. Advertising

  3. Mug

    Mug Guest

    On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    > Mug wrote:
    > > -------------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.


    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
     
    Mug, Aug 24, 2009
    #3
  4. Mug

    Mug Guest

    On Aug 24, 7:39 pm, Mug <> wrote:
    > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    >
    >
    >
    > > Mug wrote:
    > > > -------------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.

    >
    > 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
     
    Mug, Aug 24, 2009
    #4
  5. On Aug 24, 12:39 pm, Mug <> wrote:
    > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    >
    >
    >
    > > Mug wrote:
    > > > -------------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.

    >
    > 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.
     
    Joshua Maurice, Aug 24, 2009
    #5
  6. Mug wrote:
    > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    >> Mug wrote:
    >>> -------------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.


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

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

    >
    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 24, 2009
    #6
  7. Mug <> writes:

    > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    >> Mug wrote:
    >> > -------------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.

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


    --
    __Pascal Bourguignon__
     
    Pascal J. Bourguignon, Aug 25, 2009
    #7
  8. Mug

    James Kanze Guest

    On Aug 24, 6:52 pm, Mug <> wrote:
    > 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.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Aug 25, 2009
    #8
  9. Mug

    James Kanze Guest

    On Aug 24, 9:39 pm, Mug <> wrote:
    > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:


    > > Mug wrote:
    > > > -------------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.


    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).

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


    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.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Aug 25, 2009
    #9
  10. Mug

    James Kanze Guest

    On Aug 24, 9:59 pm, Joshua Maurice <> wrote:
    > On Aug 24, 12:39 pm, Mug <> 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.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Aug 25, 2009
    #10
  11. Mug

    James Kanze Guest

    On Aug 24, 10:01 pm, Victor Bazarov <> wrote:
    > Mug wrote:
    > > On Aug 24, 5:08 pm, Juha Nieminen <> wrote:
    > >> Mug wrote:
    > >>> -------------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.


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


    Not in this case.

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


    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 ;

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Aug 25, 2009
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. F. Edward Boas

    typedef and #ifdef

    F. Edward Boas, Aug 11, 2003, in forum: C++
    Replies:
    1
    Views:
    1,017
    Alf P. Steinbach
    Aug 11, 2003
  2. Chris Torek

    Re: defined(name) vs #ifdef AND #ifndef

    Chris Torek, Jul 2, 2003, in forum: C Programming
    Replies:
    0
    Views:
    832
    Chris Torek
    Jul 2, 2003
  3. Keith Thompson

    Re: defined(name) vs #ifdef AND #ifndef

    Keith Thompson, Jul 2, 2003, in forum: C Programming
    Replies:
    0
    Views:
    4,451
    Keith Thompson
    Jul 2, 2003
  4. Kenneth Porter

    scpp and expanding ifdef's

    Kenneth Porter, Oct 11, 2003, in forum: C Programming
    Replies:
    3
    Views:
    1,058
    Alan Balmer
    Oct 13, 2003
  5. John Reye
    Replies:
    14
    Views:
    810
    Tim Rentsch
    May 8, 2012
Loading...

Share This Page