Forward declarations to static variables

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • fox@scene.pl

    #1

    Forward declarations to static variables

    How do I (portably) make a forward reference to a static (I mean
    file-scope) variable?

    I've been using "extern" for years, for example:

    extern int x;
    int foo(void)
    {
    return x++;
    }
    static int x = 5;

    .... and gcc 3.4.4 and MSVC 2005 do not even warn that anything's wrong
    here.

    But gcc 4 gives me an error:

    static declaration of 'x' follows non-static declaration

    It seems that replacing "extern" with "static" makes it happy.

    I always thought that "static" means a definition (and not merely a
    declaration) for variables
    and if you want to just declare a variable then you use "extern". Now I
    cannot understand what "static int x;" actually is: just a declaration?
    or declaration and definition?
    Please note that I can remove the second "static int x" line and it
    still compiles...

    Can you explain me what C standards say about this issue and why some
    compilers don't issue a warning while gcc 4 gives an error? Is it
    because some compilers default to C89 and the other default to C9X ?

    Thanks,
    Piotr

  • Eric Sosman

    #2
    Re: Forward declarations to static variables



    fox@scene.pl wrote On 01/19/06 11:16,:[color=blue]
    > How do I (portably) make a forward reference to a static (I mean
    > file-scope) variable?
    >
    > I've been using "extern" for years, for example:
    >
    > extern int x;
    > int foo(void)
    > {
    > return x++;
    > }
    > static int x = 5;
    >
    > ... and gcc 3.4.4 and MSVC 2005 do not even warn that anything's wrong
    > here.
    >
    > But gcc 4 gives me an error:
    >
    > static declaration of 'x' follows non-static declaration
    >
    > It seems that replacing "extern" with "static" makes it happy.
    >
    > I always thought that "static" means a definition (and not merely a
    > declaration) for variables
    > and if you want to just declare a variable then you use "extern". Now I
    > cannot understand what "static int x;" actually is: just a declaration?
    > or declaration and definition?
    > Please note that I can remove the second "static int x" line and it
    > still compiles...
    >
    > Can you explain me what C standards say about this issue and why some
    > compilers don't issue a warning while gcc 4 gives an error? Is it
    > because some compilers default to C89 and the other default to C9X ?[/color]

    Both versions of the Standard say

    If, within a translation unit, the same identifier
    appears with both internal and external linkage, the
    behavior is undefined.

    That's 6.2.2/7 in C99 and 3.1.2.2/7 in Original ANSI (which
    ISO renumbered to produce C90).

    "The behavior is undefined" implies a couple of things.
    First, it means that different compilers are allowed to handle
    the situation differently; it can even happen that a single
    compiler could handle it inconsistently. Second, it means
    that the compiler is not required to complain; any diagnostic
    you may receive is just a bonus.

    The conclusion: Don't Do That. The duelling declarations
    are not valid C, in the sense that C assigns no meaning to
    them. Hence, when you write them you have no idea what the
    effect might be, no idea what you're asking the compiler to do.

    --
    Eric.Sosman@sun .com

    Comment

    • lawrence.jones@ugs.com

      #3
      Re: Forward declarations to static variables

      fox@scene.pl wrote:[color=blue]
      >
      >
      > I always thought that "static" means a definition (and not merely a
      > declaration) for variables
      > and if you want to just declare a variable then you use "extern". Now I
      > cannot understand what "static int x;" actually is: just a declaration?
      > or declaration and definition?[/color]

      It's a declaration and a *tentative* definition. That is, if no actual
      definition is found later on in the translation unit, then it will act
      as a definition, but it doesn't preclude an actual definition from
      appearing later. An actual definition includes an initializer:

      static int x; // tentative definition
      static int x = 0; // actual definition

      -Larry Jones

      Any game without push-ups, hits, burns or noogies is a sissy game. -- Calvin

      Comment

      • Rod Pemberton

        #4
        Re: Forward declarations to static variables


        <fox@scene.pl > wrote in message
        news:1137687413 .232520.120220@ g44g2000cwa.goo glegroups.com.. .[color=blue]
        > How do I (portably) make a forward reference to a static (I mean
        > file-scope) variable?
        >
        > I've been using "extern" for years, for example:
        >
        > extern int x;
        > int foo(void)
        > {
        > return x++;
        > }
        > static int x = 5;
        >
        > ... and gcc 3.4.4 and MSVC 2005 do not even warn that anything's wrong
        > here.
        >
        > But gcc 4 gives me an error:
        >
        > static declaration of 'x' follows non-static declaration
        >
        > It seems that replacing "extern" with "static" makes it happy.
        >
        > I always thought that "static" means a definition (and not merely a
        > declaration) for variables
        > and if you want to just declare a variable then you use "extern". Now I
        > cannot understand what "static int x;" actually is: just a declaration?
        > or declaration and definition?
        > Please note that I can remove the second "static int x" line and it
        > still compiles...
        >
        > Can you explain me what C standards say about this issue and why some
        > compilers don't issue a warning while gcc 4 gives an error? Is it
        > because some compilers default to C89 and the other default to C9X ?
        >
        > Thanks,
        > Piotr[/color]

        Why can't you just move the declaration to the top of the file? For
        portability, you'll probably need to remove all references to 'static'.
        'static' on variables is supposed to mean that it doesn't get exported to
        the linker. However, I've seen some compilers that treat 'static' as
        'const' and optimize away the code...


        Rod Pemberton


        Comment

        • Keith Thompson

          #5
          Re: Forward declarations to static variables

          "Rod Pemberton" <dont_have@bitb ucket.cmm> writes:
          [...][color=blue][color=green]
          >> extern int x;
          >> int foo(void)
          >> {
          >> return x++;
          >> }
          >> static int x = 5;[/color][/color]
          [...][color=blue]
          > Why can't you just move the declaration to the top of the file? For
          > portability, you'll probably need to remove all references to 'static'.
          > 'static' on variables is supposed to mean that it doesn't get exported to
          > the linker. However, I've seen some compilers that treat 'static' as
          > 'const' and optimize away the code...[/color]

          I can't imagine a compiler treating "static" as "const"; they're
          entirely different things. However, if the compiler is able to
          determine that the value of x is never modified, it can internally
          replace all references to x with a literal value 5 and remove x.
          Without the "static", it wouldn't be able to do this, because x could
          be referenced from another source file; with "static", the compiler
          knows that x exists only within the current source file.

          (Even with "static", x could still be modified in another source file
          if its address is passed to an external function, or is otherwise made
          externally visible. The compiler can still do the optimization if it
          can prove that this never happens.)

          --
          Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
          San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
          We must do something. This is something. Therefore, we must do this.

          Comment

          • Joe Wright

            #6
            Re: Forward declarations to static variables

            fox@scene.pl wrote:[color=blue]
            > How do I (portably) make a forward reference to a static (I mean
            > file-scope) variable?
            >
            > I've been using "extern" for years, for example:
            >
            > extern int x;
            > int foo(void)
            > {
            > return x++;
            > }
            > static int x = 5;
            >
            > ... and gcc 3.4.4 and MSVC 2005 do not even warn that anything's wrong
            > here.
            >
            > But gcc 4 gives me an error:
            >
            > static declaration of 'x' follows non-static declaration
            >
            > It seems that replacing "extern" with "static" makes it happy.
            >
            > I always thought that "static" means a definition (and not merely a
            > declaration) for variables
            > and if you want to just declare a variable then you use "extern". Now I
            > cannot understand what "static int x;" actually is: just a declaration?
            > or declaration and definition?
            > Please note that I can remove the second "static int x" line and it
            > still compiles...
            >
            > Can you explain me what C standards say about this issue and why some
            > compilers don't issue a warning while gcc 4 gives an error? Is it
            > because some compilers default to C89 and the other default to C9X ?
            >
            > Thanks,
            > Piotr
            >[/color]

            You seem to misunderstand the whole system. Assume a C program written
            in two or more translation units (.c files). Variables defined in these
            files outside of any function have static duration (storage class) and
            external linkage.

            For sake of argument, let's say we have a program 'foo' which consists
            of three translation units, foo.c, bar.c and baz.c plus a header, foo.h
            which is #included in each of the .c files. Further assume there is a
            single int object named x, defined in foo.c and accessable by functions
            in foo.c, bar.c and baz.c as well. This way..

            [foo.h]
            extern int x;

            [baz.c]
            #include "foo.h"
            void baz(void) {
            x = 3;
            }

            [bar.c]
            #include "foo.h"
            void bar(void) {
            x = 2;
            }

            [foo.c]
            #include <stdio.h>
            #include "foo.h"

            int x = 1;

            int main(void) {
            printf("%d\n", x);
            bar();
            printf("%d\n", x);
            baz();
            printf("%d\n", x);
            return 0;
            }

            I assume you know how to compile the three .c files and then create the
            executable. That's technically Off Topic here. :-)

            Each of foo.c, bar.c and baz.c include foo.h and so declare x an int
            somewhere. Only foo.c defines 'int x = 1;' with external linkage. Now
            bar and baz can 'see' x as if it were theirs.

            There is no case for 'static int x = 1;'.

            --
            Joe Wright
            "Everything should be made as simple as possible, but not simpler."
            --- Albert Einstein ---

            Comment

            • fox@scene.pl

              #7
              Re: Forward declarations to static variables

              > It's a declaration and a *tentative* definition.

              That is clear, thanks.
              Is it defined by C89 and supported by all C compilers (I don't care
              about pre-ANSI ones) ?
              [color=blue]
              > Why can't you just move the declaration to the top of the file?[/color]

              The real code is like this:

              #include <xmms/plugin.h>

              extern InputPlugin mod; // <-- I'll change it to static

              static void init(void)
              {
              // ...
              }

              static int is_our_file(cha r *filename)
              {
              // ...
              }

              static void play_file(char *filename)
              {
              // ...
              // (I use mod.output here)
              }

              static void pause(short paused)
              {
              mod.output->pause(paused );
              }

              static void stop(void)
              {
              // ....
              }

              static int get_time(void)
              {
              // ...
              }

              static InputPlugin mod = {
              // ...
              init,
              NULL,
              NULL,
              is_our_file,
              NULL,
              play_file,
              stop,
              pause,
              NULL,
              NULL,
              get_time,
              // these are filled by XMMS at runtime (this includes the "output"
              field):
              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
              };

              // this is exported from the compiled *.so:
              InputPlugin *get_iplugin_in fo(void)
              {
              return &mod;
              }

              Of course I could make forward declarations of my static functions,
              for example:

              static void pause(short paused);

              (I'm sure this is a declaration and never a definition)
              and then define "mod" at the top, but as you can see there are several
              static functions while there's just one "mod".
              [color=blue]
              > For portability, you'll probably need to remove all references to 'static'.[/color]

              Ehm, what?
              [color=blue]
              > 'static' on variables is supposed to mean that it doesn't get exported to
              > the linker.[/color]

              This is exactly what I want.
              [color=blue]
              > You seem to misunderstand the whole system.[/color]

              No.

              Thanks,
              Piotr

              Comment

              • Antonio Contreras

                #8
                Re: Forward declarations to static variables

                Joe Wright wrote:[color=blue]
                > fox@scene.pl wrote:[color=green]
                > > How do I (portably) make a forward reference to a static (I mean
                > > file-scope) variable?
                > >
                > > I've been using "extern" for years, for example:
                > >
                > > extern int x;
                > > int foo(void)
                > > {
                > > return x++;
                > > }
                > > static int x = 5;
                > >
                > > ... and gcc 3.4.4 and MSVC 2005 do not even warn that anything's wrong
                > > here.
                > >
                > > But gcc 4 gives me an error:
                > >
                > > static declaration of 'x' follows non-static declaration
                > >
                > > It seems that replacing "extern" with "static" makes it happy.
                > >
                > > I always thought that "static" means a definition (and not merely a
                > > declaration) for variables
                > > and if you want to just declare a variable then you use "extern". Now I
                > > cannot understand what "static int x;" actually is: just a declaration?
                > > or declaration and definition?
                > > Please note that I can remove the second "static int x" line and it
                > > still compiles...
                > >
                > > Can you explain me what C standards say about this issue and why some
                > > compilers don't issue a warning while gcc 4 gives an error? Is it
                > > because some compilers default to C89 and the other default to C9X ?
                > >
                > > Thanks,
                > > Piotr
                > >[/color]
                >
                > You seem to misunderstand the whole system.[/color]

                I didn't get this impression reading his post.

                Assume a C program written[color=blue]
                > in two or more translation units (.c files). Variables defined in these
                > files outside of any function have static duration (storage class) and
                > external linkage.
                >
                > For sake of argument, let's say we have a program 'foo' which consists
                > of three translation units, foo.c, bar.c and baz.c plus a header, foo.h
                > which is #included in each of the .c files. Further assume there is a
                > single int object named x, defined in foo.c and accessable by functions
                > in foo.c, bar.c and baz.c as well. This way..
                >
                > [foo.h]
                > extern int x;
                >
                > [baz.c]
                > #include "foo.h"
                > void baz(void) {
                > x = 3;
                > }
                >
                > [bar.c]
                > #include "foo.h"
                > void bar(void) {
                > x = 2;
                > }
                >
                > [foo.c]
                > #include <stdio.h>
                > #include "foo.h"
                >
                > int x = 1;
                >
                > int main(void) {
                > printf("%d\n", x);
                > bar();
                > printf("%d\n", x);
                > baz();
                > printf("%d\n", x);
                > return 0;
                > }[/color]

                If you compile this code with a C89 compiler you'll get undefined
                behaviour. You did not provide a prototype for bar() and baz() so the
                compiler will assume int. Since the actual return type is void, the
                behaviour is undefined (IIRC). In C99 the code is not compilable since
                a correct prototype in scope is needed.
                [color=blue]
                > I assume you know how to compile the three .c files and then create the
                > executable. That's technically Off Topic here. :-)
                >
                > Each of foo.c, bar.c and baz.c include foo.h and so declare x an int
                > somewhere. Only foo.c defines 'int x = 1;' with external linkage. Now
                > bar and baz can 'see' x as if it were theirs.
                >
                > There is no case for 'static int x = 1;'.[/color]

                How would you declare a variable with static duration, file scope and
                internal linkage if it was not in this way?

                Comment

                • pete

                  #9
                  Re: Forward declarations to static variables

                  fox@scene.pl wrote:
                  [color=blue]
                  > Of course I could make forward declarations of my static functions,
                  > for example:
                  >
                  > static void pause(short paused);[/color]

                  Why wouldn't you?
                  Too much typing?
                  [color=blue]
                  > (I'm sure this is a declaration and never a definition)
                  > and then define "mod" at the top, but as you can see there are several
                  > static functions while there's just one "mod".[/color]

                  --
                  pete

                  Comment

                  • Default User

                    #10
                    Re: Forward declarations to static variables

                    pete wrote:
                    [color=blue]
                    > fox@scene.pl wrote:
                    >[color=green]
                    > > Of course I could make forward declarations of my static functions,
                    > > for example:
                    > >
                    > > static void pause(short paused);[/color]
                    >
                    > Why wouldn't you?
                    > Too much typing?[/color]


                    Some people just prefer to define the functions in the order they'll be
                    used. With statics, there's no need for declarations for other
                    translation units.

                    I always find it easier to just put prototypes in, that way if the
                    design changes I don't end up moving functions around to get them in
                    the correct order.


                    Brian

                    Comment

                    • pete

                      #11
                      Re: Forward declarations to static variables

                      Default User wrote:[color=blue]
                      >
                      > pete wrote:
                      >[color=green]
                      > > fox@scene.pl wrote:
                      > >[color=darkred]
                      > > > Of course I could make forward declarations
                      > > > of my static functions,
                      > > > for example:
                      > > >
                      > > > static void pause(short paused);[/color]
                      > >
                      > > Why wouldn't you?
                      > > Too much typing?[/color]
                      >
                      > Some people just prefer to define the functions
                      > in the order they'll be
                      > used. With statics, there's no need for declarations for other
                      > translation units.
                      >
                      > I always find it easier to just put prototypes in, that way if the
                      > design changes I don't end up moving functions around to get them in
                      > the correct order.[/color]

                      Me too.

                      --
                      pete

                      Comment

                      • fox@scene.pl

                        #12
                        Re: Forward declarations to static variables

                        > > Of course I could make forward declarations of my static functions,[color=blue][color=green]
                        > > for example:
                        > >
                        > > static void pause(short paused);[/color]
                        >
                        > Why wouldn't you?
                        > Too much typing?[/color]

                        Yes. The problem is not one-time copy-paste work,
                        but that there would be two places to update in the future for each
                        function.
                        AFAIK, no compiler tells you when the argument names
                        in declarations/definition do not match.
                        If possible, I always avoid forward declarations (especially of
                        functions) in *.c file.

                        I have seen that some people prefer declaring all functions at the top,
                        but first it's easy to forget about declaring some functions, second
                        you
                        should probably declare all top-level variables too (for consistency).

                        The order of functions doesn't matter in the case of my XMMS plugin,
                        because they don't call each other.

                        I am still waiting for confirmation that tentative definitions of
                        statics
                        are guaranteed by C89.

                        Piotr

                        Comment

                        • lawrence.jones@ugs.com

                          #13
                          Re: Forward declarations to static variables

                          fox@scene.pl wrote [quoting me]:[color=blue]
                          >[color=green]
                          >> It's a declaration and a *tentative* definition.[/color]
                          >
                          > That is clear, thanks.
                          > Is it defined by C89 and supported by all C compilers (I don't care
                          > about pre-ANSI ones) ?[/color]

                          Yes. Prior to C89, there was no portable way to forward reference
                          static variables.

                          -Larry Jones

                          I'm so disappointed. -- Calvin

                          Comment

                          Working...