linking problem? | extern keyword

Discussion in 'C Programming' started by Stanley Rice, Nov 14, 2011.

  1. Stanley Rice

    Stanley Rice Guest

    Dear all

    I got a question about the key word 'extern', In f1.c, I define a
    variable as below:
    --------------f1.c--------------
    float var = 3.0F;

    but in file main.c, I declare it as type double
    ---------------main.c-------------
    extern double var;
    ......
    printf("%f\n", var);
    .....

    At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    f1.c is defined in type float, but I declare the var in main.c with
    type double, which is inconsistant. However, the compiler happily
    accept it. But the result isn't what I expect. It prints 0.000000
    instead of 3.0, and I couldn't find the reason here.

    For another try, I define a variable as below:
    --------------f2.c------------------
    unsigned int var_int = 4;

    in another file, say, main.c, I declare it as below
    -------------main.c----------------
    extern int var_int;
    .....
    printf("%d\n", var_int);

    This time, define var_int in type 'unsigned int' but declare it in
    type 'int' in another file, the printed result is 4, which is
    consistant with what it is previously defined.

    Could anyone what happens? why doesn't the compiler complains, and why
    the two results differs. Thanks in advance.
     
    Stanley Rice, Nov 14, 2011
    #1
    1. Advertising

  2. Stanley Rice

    Ike Naar Guest

    On 2011-11-14, Stanley Rice <> wrote:
    > I got a question about the key word 'extern', In f1.c, I define a
    > variable as below:
    > --------------f1.c--------------
    > float var = 3.0F;
    >
    > but in file main.c, I declare it as type double
    > ---------------main.c-------------
    > extern double var;
    > .....
    > printf("%f\n", var);
    > ....
    >
    > At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    > f1.c is defined in type float, but I declare the var in main.c with
    > type double, which is inconsistant. However, the compiler happily
    > accept it. But the result isn't what I expect. It prints 0.000000
    > instead of 3.0, and I couldn't find the reason here.


    The usual way to solve this problem is to use a header file,
    say f1.h, that contains the external declarations of f1.c .

    /* f1.h */
    extern float var;

    Then #include f1.h in f1.c and in every file that uses var.
    So, in main.c, instead of having

    extern double var;

    use

    #include "f1.h"
     
    Ike Naar, Nov 14, 2011
    #2
    1. Advertising

  3. Stanley Rice <> wrote:
    > Dear all


    > I got a question about the key word 'extern', In f1.c, I define a
    > variable as below:
    > --------------f1.c--------------
    > float var = 3.0F;


    > but in file main.c, I declare it as type double
    > ---------------main.c-------------
    > extern double var;
    > .....
    > printf("%f\n", var);
    > ....


    > At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    > f1.c is defined in type float, but I declare the var in main.c with
    > type double, which is inconsistant. However, the compiler happily
    > accept it.


    That was to be expected. When the compiler compiles main.c
    it has no idea what is in f1.c and vice versa. Remember,
    the compiler is always working on a single C file and it
    has to trust you if you tell it that you defined a vari-
    able in another file and that it has the correct type.

    > But the result isn't what I expect. It prints 0.000000
    > instead of 3.0, and I couldn't find the reason here.


    Well, when the compiler is finished the linker got to work
    out things. And the compiler tells the linker that for
    main.o it needs a variable with the name 'var' from some-
    where else, but it doesn't tell the linker about the type,
    that's something you must have gotten right. And since the
    linker finds a variable named 'var' it's quite happy and
    also can't detect this error. But when the program finally
    is run it will try to access 'var' in main.c as a double
    despite it being only a float. The result is anyones guess
    since the sizes of float and double are rather likely to
    be different as are their bit representations.

    > For another try, I define a variable as below:
    > --------------f2.c------------------
    > unsigned int var_int = 4;


    > in another file, say, main.c, I declare it as below
    > -------------main.c----------------
    > extern int var_int;
    > ....
    > printf("%d\n", var_int);


    > This time, define var_int in type 'unsigned int' but declare it in
    > type 'int' in another file, the printed result is 4, which is
    > consistant with what it is previously defined.


    Here's the same problem but since 'int' and 'unsigned int'
    have the same size and more or less the same bit represen-
    tation (i.e. if you compare the bit pattern for an int set
    to 4 and that of an unsigned int, also set to 4 they will
    be the same) you just get away with it

    If you would have done it the other way round, i.e define
    'var' as an int and set it to a negative value and then
    declare 'var' in main.c as unsigned int you would have
    gotten some strange number printed out.

    > Could anyone what happens? why doesn't the compiler complains, and why
    > the two results differs. Thanks in advance.


    The compiler can't complain because it doesn't know any-
    thing about the "real" 'var' variable while its com-
    piling main.c (if it would know about it the 'extern'
    declaration would be rather redundant). And this leads
    to your program using a float variable as if it were a
    double, which it isn't.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, Nov 14, 2011
    #3
  4. Stanley Rice

    James Kuyper Guest

    On 11/14/2011 07:20 AM, Stanley Rice wrote:
    > Dear all
    >
    > I got a question about the key word 'extern', In f1.c, I define a
    > variable as below:
    > --------------f1.c--------------
    > float var = 3.0F;
    >
    > but in file main.c, I declare it as type double
    > ---------------main.c-------------
    > extern double var;
    > .....
    > printf("%f\n", var);
    > ....
    >
    > At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    > f1.c is defined in type float, but I declare the var in main.c with
    > type double, which is inconsistant. However, the compiler happily
    > accept it. But the result isn't what I expect. It prints 0.000000
    > instead of 3.0, and I couldn't find the reason here.


    The reason is that such a mis-match makes the behavior of your program
    undefined. When you have separate compile-link phases, it's not possible
    for the compiler to notice this discrepancy, it doesn't have enough
    information. In principle, a linker could generate such a message, but
    the C standard does not require it, and most will not provide one.

    > For another try, I define a variable as below:
    > --------------f2.c------------------
    > unsigned int var_int = 4;
    >
    > in another file, say, main.c, I declare it as below
    > -------------main.c----------------
    > extern int var_int;
    > ....
    > printf("%d\n", var_int);
    >
    > This time, define var_int in type 'unsigned int' but declare it in
    > type 'int' in another file, the printed result is 4, which is
    > consistant with what it is previously defined.
    >
    > Could anyone what happens? why doesn't the compiler complains, and why
    > the two results differs. Thanks in advance.


    In principle, the behavior is just as undefined in this case as in the
    other. However, when the behavior is undefined, that means that anything
    is permitted by the C standard, including having the program do exactly
    what you incorrectly thought it was required to do. In this case, since
    the C standard mandates that positive integer values have exactly the
    same representation in the corresponding unsigned type, it is very
    likely to work on most implementations. No such requirement applied in
    the double/float case.
    --
    James Kuyper
     
    James Kuyper, Nov 14, 2011
    #4
  5. On 2011-11-14, Stanley Rice <> wrote:
    > Dear all
    >
    > I got a question about the key word 'extern', In f1.c, I define a
    > variable as below:
    > --------------f1.c--------------
    > float var = 3.0F;
    >
    > but in file main.c, I declare it as type double
    > ---------------main.c-------------
    > extern double var;
    > .....
    > printf("%f\n", var);
    > ....
    >
    > At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    > f1.c is defined in type float, but I declare the var in main.c with
    > type double, which is inconsistant. However, the compiler happily
    > accept it. But the result isn't what I expect. It prints 0.000000
    > instead of 3.0, and I couldn't find the reason here.


    For the sake of separate compilation no tests are done regarding
    interfaces during linkage of the separate objects of your program.

    The behavior of your program is unspecified as stated in the standard
    (6.2.7p2):

    All declarations that refer to the same object shall have compatible
    type; otherwise, the behavior is undefined.

    Thus, it is no use to interpret the results of your program.

    --
    qcar
     
    Quentin Carbonneaux, Nov 14, 2011
    #5
  6. Stanley Rice

    Stanley Rice Guest

    On Nov 14, 8:52 pm, Ike Naar <> wrote:
    > On 2011-11-14, Stanley Rice <> wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > I got a question about the key word 'extern', In f1.c, I define a
    > > variable as below:
    > > --------------f1.c--------------
    > > float var = 3.0F;

    >
    > > but in file main.c, I declare it as type double
    > > ---------------main.c-------------
    > > extern double var;
    > > .....
    > > printf("%f\n", var);
    > > ....

    >
    > > At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    > > f1.c is defined in type float, but I declare the var in main.c with
    > > type double, which is inconsistant. However, the compiler happily
    > > accept it. But the result isn't what I expect. It prints 0.000000
    > > instead of 3.0, and I couldn't find the reason here.

    >
    > The usual way to solve this problem is to use a header file,
    > say f1.h, that contains the external declarations of f1.c .
    >
    > /* f1.h */
    > extern float var;
    >
    > Then #include f1.h in f1.c and in every file that uses var.
    > So, in main.c, instead of having
    >
    >   extern double var;
    >
    > use
    >
    >   #include "f1.h"


    Yeah, you are right. And I know how to solve the problem as you said
    above. Here I declare 'var' deliberately in type double, and want to
    know why the compiler happily accept it and how it works.
     
    Stanley Rice, Nov 15, 2011
    #6
  7. Stanley Rice

    James Kuyper Guest

    On 11/15/2011 12:42 AM, Stanley Rice wrote:
    > On Nov 14, 8:52�pm, Ike Naar <> wrote:
    >> On 2011-11-14, Stanley Rice <> wrote:

    ....
    >>> I got a question about the key word 'extern', In f1.c, I define a
    >>> variable as below:
    >>> --------------f1.c--------------
    >>> float var = 3.0F;

    >>
    >>> but in file main.c, I declare it as type double
    >>> ---------------main.c-------------
    >>> extern double var;
    >>> .....
    >>> printf("%f\n", var);
    >>> ....

    >>
    >>> At first, I guess that the compiler(gcc) will shout to me, as 'var' in
    >>> f1.c is defined in type float, but I declare the var in main.c with
    >>> type double, which is inconsistant. However, the compiler happily
    >>> accept it. But the result isn't what I expect. It prints 0.000000
    >>> instead of 3.0, and I couldn't find the reason here.

    ....
    > Yeah, you are right. And I know how to solve the problem as you said
    > above. Here I declare 'var' deliberately in type double, and want to
    > know why the compiler happily accept it and how it works.


    I thought that your question had already been answered, but you wrote
    "want to know" in the present tense, implying that you're still looking
    for something more than the answers you've already received. Here's
    another explanation, I hope it may help:

    The compiler happily accepts your modules because it never sees the
    discrepancy; it only sees f1.c, or main.c; it never looks at both at the
    same time. That's why the solution is to put the declaration in a header
    file that is shared by both translation units.

    The linker could have enough information to detect the problem, if the
    object file format permits the storage of the relevant information, and
    if the compiler provides it. However, such information is not needed for
    the linker to do it's main job, and is therefore not necessarily
    available to it. That's part of the reason why the C standard does not
    require generation of any diagnostic message for this kind of problem.

    As for how it works - the definition of var in f1.c causes a piece of
    memory to be set aside that is sufficiently large and correctly aligned
    to store an object of type 'float'. That piece of memory is extremely
    unlikely to be large enough to store an object of type 'double', and
    might not be correctly aligned to store one.

    The declaration of var as a double with external linkage in main.c
    causes the linker to determine the address reserved for an identifier
    with external linkage named 'var' and to insert that address into the
    locations in the code implementing main() that need the address of 'var'
    (I speak of the way linkers work on the systems I'm most familiar with -
    there probably are other ways that can be used to achieve the same
    effect). It doesn't need to know the type of thing stored at that
    address in order to do this.

    When executing the instructions implementing main() that are supposed to
    refer to value of 'var', the program tries to retrieve the value of an
    object of type 'double' that it assumes is stored that address. Since
    there is no such object, this is where things are likely to go wrong.
    The most likely situation is that it looked at sizeof(double) bytes of
    memory, starting with the bytes storing the f1.c 'var', but also
    including additional bytes of memory that may have been allocated for
    some other purpose entirely. Those bytes might not even be ones that
    your process has permission to access. If it does have such permissions,
    it will interpret those bytes as if they contained a representation of a
    'double' value; they need not contain a valid representation, and are
    extremely unlikely to contain a valid representation of the same value
    that was stored by f1.c in 'var'.

    Does that answer your question?
    --
    James Kuyper
     
    James Kuyper, Nov 15, 2011
    #7
    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. Thomas Matthews
    Replies:
    5
    Views:
    2,557
    tom_usenet
    Aug 2, 2004
  2. tweak

    keyword extern

    tweak, Jun 26, 2004, in forum: C Programming
    Replies:
    18
    Views:
    669
    Dan Pop
    Jun 29, 2004
  3. ooze

    how to use the keyword extern in c?

    ooze, Aug 25, 2004, in forum: C Programming
    Replies:
    16
    Views:
    670
    Dan Pop
    Aug 30, 2004
  4. siliconwafer

    Use of 'extern' keyword

    siliconwafer, Jul 28, 2005, in forum: C Programming
    Replies:
    5
    Views:
    403
    Kenny McCormack
    Jul 31, 2005
  5. Andre
    Replies:
    5
    Views:
    567
    Keith Thompson
    Jul 17, 2012
Loading...

Share This Page