Forward declaration of static variable

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jef Driesen

    Forward declaration of static variable

    I have the following problem in a C project (but that also needs to
    compile with a C++ compiler). I'm using a virtual function table, that
    looks like this in the header file:

    typedef struct device_t {
    const device_backend_ t *backend;
    ...
    } device_t;

    typedef struct device_backend_ t {
    int (*read) (device_t *device, /* parameters */);
    int (*write) (device_t *device, /* parameters */);
    ...
    } device_backend_ t;

    Now when I want to implement a new backend, I write the necessary
    functions in the source file:

    int mydevice_read (device_t *device, /* parameters */)
    {
    ...
    }

    int mydevice_write (device_t *device, /* parameters */)
    {
    ...
    }

    static const device_backend_ t mydevice_backen d = {
    mydevice_read,
    mydevice_write,
    ...
    };

    So far no problem, but in a number of those functions, I need to have
    access to the "mydevice_backe nd" variable. For instance to check whether
    the backend pointer is the correct one. How can I forward declare this
    variable properly?

    When I add

    static const device_backend_ t reefnet_sensusp ro_device_backe nd;

    to the top of my source file, it works with the gcc compiler, but I'm
    not sure this is valid according to the C (or C++) standard. It
    certainly doesn't compile with msvc (in C++ mode). It complains about a
    redefinition.

    How can I make this work? I could move the definition of the
    "mydevice_backe nd" variable to the top of the source file and forward
    declare each function inside the structure, but being able to forward
    declare the variable itself would be much more elegant.
  • Ben Bacarisse

    #2
    Re: Forward declaration of static variable

    Jef Driesen <jefdriesen@hot mail.com.invali dwrites:
    I have the following problem in a C project (but that also needs to
    compile with a C++ compiler). I'm using a virtual function table, that
    looks like this in the header file:
    >
    typedef struct device_t {
    const device_backend_ t *backend;
    ...
    } device_t;
    >
    typedef struct device_backend_ t {
    int (*read) (device_t *device, /* parameters */);
    int (*write) (device_t *device, /* parameters */);
    ...
    } device_backend_ t;
    >
    Now when I want to implement a new backend, I write the necessary
    functions in the source file:
    >
    int mydevice_read (device_t *device, /* parameters */)
    {
    ...
    }
    >
    int mydevice_write (device_t *device, /* parameters */)
    {
    ...
    }
    >
    static const device_backend_ t mydevice_backen d = {
    mydevice_read,
    mydevice_write,
    ...
    };
    >
    So far no problem, but in a number of those functions, I need to have
    access to the "mydevice_backe nd" variable. For instance to check
    whether the backend pointer is the correct one. How can I forward
    declare this variable properly?
    >
    When I add
    >
    static const device_backend_ t reefnet_sensusp ro_device_backe nd;
    I think you mean

    static const device_backend_ t mydevice_backen d;

    At least that is the name you use above and below.
    to the top of my source file, it works with the gcc compiler, but I'm
    not sure this is valid according to the C (or C++) standard. It
    certainly doesn't compile with msvc (in C++ mode). It complains about
    a redefinition.
    You may get a better answer in comp.lang.c++ since this whole area is
    one in which there are subtle but important differences between C and
    C++. If you need the code to pass through a C++ compiler, then you
    are writing C++ (no matter how much it looks like C!) and you need C++
    experts.

    I you had said it failed on MSVC in C mode I would have written: It is
    likely that exact details are required so please construct a minimal
    example that compiles in one but not the other compiler (you are 99%
    there already with what you outlined).

    The reason I say this is that "at the top" is not clear enough for
    this problem because the declaration of the static struct is what is
    called (in C) a tentative definition and special rules apply. Since
    it has internal linkage, it must be a complete type (by the standard)
    but gcc accepts it even when incomplete (it is allowed to -- there is
    no requirement for a diagnostic message).

    [In fact I wrote that before I saw your "in C++ mode" remark. I
    suspect you don't need C's answer to this question.]
    How can I make this work? I could move the definition of the
    "mydevice_backe nd" variable to the top of the source file and forward
    declare each function inside the structure, but being able to forward
    declare the variable itself would be much more elegant.
    You can in C, but maybe not in C++. The C++ people can tell you.

    --
    Ben.

    Comment

    • zaimoni@zaimoni.com

      #3
      Re: Forward declaration of static variable

      On Aug 23, 2:57 am, Jef Driesen <jefdrie...@hot mail.com.invali d>
      wrote:
      I have the following problem in a C project (but that also needs to
      compile with a C++ compiler). I'm using a virtual function table, that
      looks like this in the header file:
      >
      typedef struct device_t {
      const device_backend_ t *backend;
      ...
      >
      } device_t;
      >
      typedef struct device_backend_ t {
      int (*read) (device_t *device, /* parameters */);
      int (*write) (device_t *device, /* parameters */);
      ...
      >
      } device_backend_ t;
      .....
      So far no problem, but in a number of those functions, I need to have
      access to the "mydevice_backe nd" variable. For instance to check whether
      the backend pointer is the correct one. How can I forward declare this
      variable properly?
      >
      When I add
      >
      static const device_backend_ t reefnet_sensusp ro_device_backe nd;
      >
      to the top of my source file, it works with the gcc compiler, but I'm
      not sure this is valid according to the C (or C++) standard. It
      certainly doesn't compile with msvc (in C++ mode). It complains about a
      redefinition.
      Just to be clear, does g++ accept that, or just gcc?

      In C(99), that is a tentative definition; it can use a later
      initializer to do the actual initialization. [C99 standard: 6.9.2
      paragraph 2] Tentative definitions were intentionally removed from C+
      +98 [Informative Annex C.2.2 paragraph 1]; this indeed is a
      redefinition in C++.

      From what you describe, I don't think extern would be a good idea
      (that should work for forward-declaring a file-scope variable in both
      C and C++).
      How can I make this work? I could move the definition of the
      "mydevice_backe nd" variable to the top of the source file and forward
      declare each function inside the structure, but being able to forward
      declare the variable itself would be much more elegant.
      Assuming static is the correct linkage, I'd just forward-declare the
      functions to be portable.

      Comment

      • Jef Driesen

        #4
        Re: Forward declaration of static variable

        Ben Bacarisse wrote:
        Jef Driesen <jefdriesen@hot mail.com.invali dwrites:
        >
        >I have the following problem in a C project (but that also needs to
        >compile with a C++ compiler). I'm using a virtual function table, that
        >looks like this in the header file:
        >>
        >typedef struct device_t {
        > const device_backend_ t *backend;
        > ...
        >} device_t;
        >>
        >typedef struct device_backend_ t {
        > int (*read) (device_t *device, /* parameters */);
        > int (*write) (device_t *device, /* parameters */);
        > ...
        >} device_backend_ t;
        >>
        >Now when I want to implement a new backend, I write the necessary
        >functions in the source file:
        >>
        >int mydevice_read (device_t *device, /* parameters */)
        >{
        > ...
        >}
        >>
        >int mydevice_write (device_t *device, /* parameters */)
        >{
        > ...
        >}
        >>
        >static const device_backend_ t mydevice_backen d = {
        > mydevice_read,
        > mydevice_write,
        > ...
        >};
        >>
        >So far no problem, but in a number of those functions, I need to have
        >access to the "mydevice_backe nd" variable. For instance to check
        >whether the backend pointer is the correct one. How can I forward
        >declare this variable properly?
        >>
        >When I add
        >>
        >static const device_backend_ t reefnet_sensusp ro_device_backe nd;
        >
        I think you mean
        >
        static const device_backend_ t mydevice_backen d;
        >
        At least that is the name you use above and below.
        You're correct. This was a copy-and-paste error.
        >to the top of my source file, it works with the gcc compiler, but I'm
        >not sure this is valid according to the C (or C++) standard. It
        >certainly doesn't compile with msvc (in C++ mode). It complains about
        >a redefinition.
        >
        You may get a better answer in comp.lang.c++ since this whole area is
        one in which there are subtle but important differences between C and
        C++. If you need the code to pass through a C++ compiler, then you
        are writing C++ (no matter how much it looks like C!) and you need C++
        experts.
        >
        I you had said it failed on MSVC in C mode I would have written: It is
        likely that exact details are required so please construct a minimal
        example that compiles in one but not the other compiler (you are 99%
        there already with what you outlined).
        >
        The reason I say this is that "at the top" is not clear enough for
        this problem because the declaration of the static struct is what is
        called (in C) a tentative definition and special rules apply. Since
        it has internal linkage, it must be a complete type (by the standard)
        but gcc accepts it even when incomplete (it is allowed to -- there is
        no requirement for a diagnostic message).
        With "at the top" I meant after the definition of device_t and
        device_backend_ t types, but right before the mydevice_read,
        mydevice_write functions.
        [In fact I wrote that before I saw your "in C++ mode" remark. I
        suspect you don't need C's answer to this question.]
        The C++ mode is only used for compiling in msvc, because I'm using a
        number of C99 features (variable declarations anywere in a code block),
        that are not supported in the msvc C compiler. In linux, I am compiling
        in C99 mode with gcc.
        >How can I make this work? I could move the definition of the
        >"mydevice_back end" variable to the top of the source file and forward
        >declare each function inside the structure, but being able to forward
        >declare the variable itself would be much more elegant.
        >
        You can in C, but maybe not in C++. The C++ people can tell you.

        Comment

        • Jef Driesen

          #5
          Re: Forward declaration of static variable

          zaimoni@zaimoni .com wrote:
          On Aug 23, 2:57 am, Jef Driesen <jefdrie...@hot mail.com.invali d>
          wrote:
          >I have the following problem in a C project (but that also needs to
          >compile with a C++ compiler). I'm using a virtual function table, that
          >looks like this in the header file:
          >>
          >typedef struct device_t {
          > const device_backend_ t *backend;
          > ...
          >>
          >} device_t;
          >>
          >typedef struct device_backend_ t {
          > int (*read) (device_t *device, /* parameters */);
          > int (*write) (device_t *device, /* parameters */);
          > ...
          >>
          >} device_backend_ t;
          >
          ....
          >
          >So far no problem, but in a number of those functions, I need to have
          >access to the "mydevice_backe nd" variable. For instance to check whether
          >the backend pointer is the correct one. How can I forward declare this
          >variable properly?
          >>
          >When I add
          >>
          >static const device_backend_ t mydevice_backen d;
          >>
          >to the top of my source file, it works with the gcc compiler, but I'm
          >not sure this is valid according to the C (or C++) standard. It
          >certainly doesn't compile with msvc (in C++ mode). It complains about a
          >redefinition .
          >
          Just to be clear, does g++ accept that, or just gcc?
          gcc in C99 mode. I didn't try with g++ yet.
          In C(99), that is a tentative definition; it can use a later
          initializer to do the actual initialization. [C99 standard: 6.9.2
          paragraph 2] Tentative definitions were intentionally removed from C+
          +98 [Informative Annex C.2.2 paragraph 1]; this indeed is a
          redefinition in C++.
          >
          From what you describe, I don't think extern would be a good idea
          (that should work for forward-declaring a file-scope variable in both
          C and C++).
          How would I use extern here?
          >How can I make this work? I could move the definition of the
          >"mydevice_back end" variable to the top of the source file and forward
          >declare each function inside the structure, but being able to forward
          >declare the variable itself would be much more elegant.
          >
          Assuming static is the correct linkage, I'd just forward-declare the
          functions to be portable.
          Static is correct. The mydevice_backen d variable only needs to be
          "visible" at file-scope.

          Comment

          • Barry Schwarz

            #6
            Re: Forward declaration of static variable

            On Sat, 23 Aug 2008 09:57:31 +0200, Jef Driesen
            <jefdriesen@hot mail.com.invali dwrote:
            >I have the following problem in a C project (but that also needs to
            >compile with a C++ compiler). I'm using a virtual function table, that
            Do you mean you are writing a C++ program this will be used by a
            project that is mostly in C or do you need a program that compiles
            correctly in both? I will assume the latter. In spite of the
            similarity in the language names and a good deal of common syntax, the
            two are separate languages. Trying to write code that will compile in
            both will force you to limit yourself to the common subset and will
            also require you to make choices which are undesirable in at least one
            of the languages.
            >looks like this in the header file:
            >
            >typedef struct device_t {
            const device_backend_ t *backend;
            In C, the structure tag is not a type. Before this typedef, add the
            "incomplete " typedef
            typedef struct device_backend_ t device_backend_ t;
            so that the type device_backend_ t is known and
            ...
            >} device_t;
            >
            >typedef struct device_backend_ t {
            then change this typedef to a simple structure declaration.
            int (*read) (device_t *device, /* parameters */);
            int (*write) (device_t *device, /* parameters */);
            ...
            >} device_backend_ t;
            >
            >Now when I want to implement a new backend, I write the necessary
            >functions in the source file:
            >
            >int mydevice_read (device_t *device, /* parameters */)
            >{
            ...
            >}
            >
            >int mydevice_write (device_t *device, /* parameters */)
            >{
            ...
            >}
            >
            >static const device_backend_ t mydevice_backen d = {
            mydevice_read,
            mydevice_write,
            ...
            >};
            >
            >So far no problem, but in a number of those functions, I need to have
            >access to the "mydevice_backe nd" variable. For instance to check whether
            >the backend pointer is the correct one. How can I forward declare this
            >variable properly?
            >
            >When I add
            >
            >static const device_backend_ t reefnet_sensusp ro_device_backe nd;
            >
            >to the top of my source file, it works with the gcc compiler, but I'm
            >not sure this is valid according to the C (or C++) standard. It
            Defining a static variable a file scope is valid. As with any
            "global" variable, it is visible to every function within the source
            file and exists for the life of the program. Since it is static, it
            has internal linkage which means the name of the variable will not be
            exported to the linker. If another source file uses the same variable
            name, it will represent a different variable. Since you don't provide
            initialization for this object with static duration, it will
            automatically be initialized to the appropriate form of zero. As the
            structure contains two pointers, they will both be set to NULL. But
            because you declare the structure as const, you will not be able to
            change the value of either pointer.
            >certainly doesn't compile with msvc (in C++ mode). It complains about a
            >redefinition .
            Since the only thing being defined is the object named
            reefnet...backe nd, you must have another definition of that object in
            code that precedes this definition. It could be in a header (which
            should never have definitions anyway).
            >
            >How can I make this work? I could move the definition of the
            What move? Your previous paragraph said it was already at the top.
            Where is it really?
            >"mydevice_back end" variable to the top of the source file and forward
            >declare each function inside the structure, but being able to forward
            >declare the variable itself would be much more elegant.
            If you put your struct declarations/typedefs and prototypes for each
            function in a header and include the header before any of your
            definitions, you can define this object at the top of your code and
            initialize it to point to the functions you want.

            file.h:
            typedef struct device_backend_ t device_backend_ t;

            typedef struct device_t {
            const device_backend_ t *backend;
            ...
            } device_t;

            struct device_backend_ t {
            int (*read) (device_t *device, /* parameters */);
            int (*write) (device_t *device, /* parameters */);
            ...
            };

            int mydevice_read (device_t *device, /* parameters */);

            int mydevice_write (device_t *device, /* parameters */);

            --------------------------------------------------------------

            file.c:
            #include "file.h"

            static const device_backend_ t mydevice_backen d = {
            mydevice_read,
            mydevice_write,
            ...
            };

            static const device_backend_ t reefnet_sensusp ro_device_backe nd =
            {...};

            main and mydevice_read etc to follow.

            --
            Remove del for email

            Comment

            • Ben Bacarisse

              #7
              Re: Forward declaration of static variable

              Jef Driesen <jefdriesen@hot mail.com.invali dwrites:
              Ben Bacarisse wrote:
              <snip>
              >The reason I say this is that "at the top" is not clear enough for
              >this problem because the declaration of the static struct is what is
              >called (in C) a tentative definition and special rules apply. Since
              >it has internal linkage, it must be a complete type (by the standard)
              >but gcc accepts it even when incomplete (it is allowed to -- there is
              >no requirement for a diagnostic message).
              >
              With "at the top" I meant after the definition of device_t and
              device_backend_ t types, but right before the mydevice_read,
              mydevice_write functions.
              OK, then at that point the type is not incomplete and a C compiler
              should take that as a tentative defintions -- one that gets "rounded
              out" by the later details. I understand that this is true in C90 as
              well as in C99 (I am less sure of some details of C90). I.e. if this
              were all you were doing, you would not need to push MSVC into C++ mode
              since it complies (with the right switches) to C90.
              >[In fact I wrote that before I saw your "in C++ mode" remark. I
              >suspect you don't need C's answer to this question.]
              >
              The C++ mode is only used for compiling in msvc, because I'm using a
              number of C99 features (variable declarations anywere in a code
              block), that are not supported in the msvc C compiler. In linux, I am
              compiling in C99 mode with gcc.
              I see. Other parts of the code require more than MSVC C offers. It
              seems daft that MSVC does not have a "near" C99 mode, but that is the
              way the world is. As soon as you take C++ sematics, const changes and
              tentative definitions are lost. Is another compiler an option for you
              Windows build?

              If you do ask in comp.lang.c++ I suspect the answers will involve
              using more C++ features since, having just had a peek, I see the C++
              standard is very clear that tentative definitions are out.

              [Ah! I see this is now cross-posted so my assertions about C++ will
              be tested -- just ignore the phrases "if you ask in...".]

              --
              Ben.

              Comment

              • zaimoni@zaimoni.com

                #8
                Re: Forward declaration of static variable

                On Aug 24, 1:34 am, Jef Driesen <jefdrie...@hot mail.com.invali d>
                wrote:
                zaim...@zaimoni .com wrote:
                On Aug 23, 2:57 am, Jef Driesen <jefdrie...@hot mail.com.invali d>
                wrote:
                I have the following problem in a C project (but that also needs to
                compile with a C++ compiler). I'm using a virtual function table, that
                looks like this in the header file:
                >
                typedef struct device_t {
                const device_backend_ t *backend;
                ...
                >
                } device_t;
                >
                typedef struct device_backend_ t {
                int (*read) (device_t *device, /* parameters */);
                int (*write) (device_t *device, /* parameters */);
                ...
                >
                } device_backend_ t;
                >
                ....
                >
                So far no problem, but in a number of those functions, I need to have
                access to the "mydevice_backe nd" variable. For instance to check whether
                the backend pointer is the correct one. How can I forward declare this
                variable properly?
                >
                When I add
                >
                static const device_backend_ t mydevice_backen d;
                >
                to the top of my source file, it works with the gcc compiler, but I'm
                not sure this is valid according to the C (or C++) standard. It
                certainly doesn't compile with msvc (in C++ mode). It complains about a
                redefinition.
                >
                Just to be clear, does g++ accept that, or just gcc?
                >
                gcc in C99 mode. I didn't try with g++ yet.
                >
                In C(99), that is a tentative definition; it can use a later
                initializer to do the actual initialization. [C99 standard: 6.9.2
                paragraph 2] Tentative definitions were intentionally removed from C+
                +98 [Informative Annex C.2.2 paragraph 1]; this indeed is a
                redefinition in C++.
                >
                From what you describe, I don't think extern would be a good idea
                (that should work for forward-declaring a file-scope variable in both
                C and C++).
                >
                How would I use extern here?
                Since the full definition is later on in the same file, use

                extern const device_backend_ t mydevice_backen d;

                to get the forward declaration in both C and C++. Unfortunately,
                locking down an extern declaration to file scope is feasible only in C+
                + (wrap both the forward declaration, and the actual definition, in an
                anonymous namespace).

                If your coding standards tolerate the C preprocessor, something like
                this (subject to actual compile testing not done here) would work by
                giving each language what it wants:

                #ifdef __cplusplus
                namespace {
                extern const device_backend_ t mydevice_backen d;
                }
                #else
                static const device_backend_ t mydevice_backen d;
                #endif

                (also using the preprocessor to wrap the actual definition in an
                anonymous namespace for C++.)

                Comment

                • Jef Driesen

                  #9
                  Re: Forward declaration of static variable

                  Barry Schwarz wrote:
                  On Sat, 23 Aug 2008 09:57:31 +0200, Jef Driesen
                  <jefdriesen@hot mail.com.invali dwrote:
                  >
                  >I have the following problem in a C project (but that also needs to
                  >compile with a C++ compiler). I'm using a virtual function table, that
                  >
                  Do you mean you are writing a C++ program this will be used by a
                  project that is mostly in C or do you need a program that compiles
                  correctly in both? I will assume the latter. In spite of the
                  similarity in the language names and a good deal of common syntax, the
                  two are separate languages. Trying to write code that will compile in
                  both will force you to limit yourself to the common subset and will
                  also require you to make choices which are undesirable in at least one
                  of the languages.
                  It's a C library. The reason why I would like to be able to compile it
                  with a C++ compiler is that I'm using a number of C99 features (variable
                  declarations anywhere in a code block). Unfortunately the msvc C
                  compiler does not support C99, but those features are supported in C++,
                  so I'm trying to make it build in C++ mode.
                  >looks like this in the header file:
                  >>
                  >typedef struct device_t {
                  > const device_backend_ t *backend;
                  >
                  In C, the structure tag is not a type. Before this typedef, add the
                  "incomplete " typedef
                  typedef struct device_backend_ t device_backend_ t;
                  so that the type device_backend_ t is known and
                  >
                  > ...
                  >} device_t;
                  >>
                  >typedef struct device_backend_ t {
                  >
                  then change this typedef to a simple structure declaration.
                  I'm doing it like that in my source code. I omitted the forward
                  declarations in this post to make it shorter.
                  > int (*read) (device_t *device, /* parameters */);
                  > int (*write) (device_t *device, /* parameters */);
                  > ...
                  >} device_backend_ t;
                  >>
                  >Now when I want to implement a new backend, I write the necessary
                  >functions in the source file:
                  >>
                  >int mydevice_read (device_t *device, /* parameters */)
                  >{
                  > ...
                  >}
                  >>
                  >int mydevice_write (device_t *device, /* parameters */)
                  >{
                  > ...
                  >}
                  >>
                  >static const device_backend_ t mydevice_backen d = {
                  > mydevice_read,
                  > mydevice_write,
                  > ...
                  >};
                  >>
                  >So far no problem, but in a number of those functions, I need to have
                  >access to the "mydevice_backe nd" variable. For instance to check whether
                  >the backend pointer is the correct one. How can I forward declare this
                  >variable properly?
                  >>
                  >When I add
                  >>
                  >static const device_backend_ t reefnet_sensusp ro_device_backe nd;
                  >>
                  >to the top of my source file, it works with the gcc compiler, but I'm
                  >not sure this is valid according to the C (or C++) standard. It
                  >
                  Defining a static variable a file scope is valid. As with any
                  "global" variable, it is visible to every function within the source
                  file and exists for the life of the program. Since it is static, it
                  has internal linkage which means the name of the variable will not be
                  exported to the linker. If another source file uses the same variable
                  name, it will represent a different variable. Since you don't provide
                  initialization for this object with static duration, it will
                  automatically be initialized to the appropriate form of zero. As the
                  structure contains two pointers, they will both be set to NULL. But
                  because you declare the structure as const, you will not be able to
                  change the value of either pointer.
                  >
                  >certainly doesn't compile with msvc (in C++ mode). It complains about a
                  >redefinition .
                  >
                  Since the only thing being defined is the object named
                  reefnet...backe nd, you must have another definition of that object in
                  code that precedes this definition. It could be in a header (which
                  should never have definitions anyway).
                  Sorry, that was a copy-and-paste error. The variable was supposed to be
                  named "mydevice_backe nd".
                  >How can I make this work? I could move the definition of the
                  >
                  What move? Your previous paragraph said it was already at the top.
                  Where is it really?
                  >
                  >"mydevice_back end" variable to the top of the source file and forward
                  >declare each function inside the structure, but being able to forward
                  >declare the variable itself would be much more elegant.
                  I only have a declaration (without any initialization) at the top. The
                  initialization is done after the implementation of the mydevice_*
                  functions. So the file looks like this:

                  static const device_backend_ t mydevice_backen d;

                  int mydevice_read (device_t *device, /* parameters */)
                  {
                  ...
                  }

                  int mydevice_write (device_t *device, /* parameters */)
                  {
                  ...
                  }

                  static const device_backend_ t mydevice_backen d = {
                  mydevice_read,
                  mydevice_write,
                  ...
                  };

                  With "moving to the top", I meant forward declaring the functions at the
                  top of the file, so the initialization can be done at the top as well.
                  Now will look like this:

                  int mydevice_read (device_t *device, /* parameters */);
                  int mydevice_write (device_t *device, /* parameters */);

                  static const device_backend_ t mydevice_backen d = {
                  mydevice_read,
                  mydevice_write,
                  ...
                  };

                  int mydevice_read (device_t *device, /* parameters */)
                  {
                  ...
                  }

                  int mydevice_write (device_t *device, /* parameters */)
                  {
                  ...
                  }

                  But in that case I have to forward declare every single function that is
                  listed in the virtual function table, while all I need would be a
                  forward declaration of the "mydevice_backe nd" variable.
                  If you put your struct declarations/typedefs and prototypes for each
                  function in a header and include the header before any of your
                  definitions, you can define this object at the top of your code and
                  initialize it to point to the functions you want.
                  >
                  file.h:
                  typedef struct device_backend_ t device_backend_ t;
                  >
                  typedef struct device_t {
                  const device_backend_ t *backend;
                  ...
                  } device_t;
                  >
                  struct device_backend_ t {
                  int (*read) (device_t *device, /* parameters */);
                  int (*write) (device_t *device, /* parameters */);
                  ...
                  };
                  >
                  int mydevice_read (device_t *device, /* parameters */);
                  >
                  int mydevice_write (device_t *device, /* parameters */);
                  >
                  --------------------------------------------------------------
                  >
                  file.c:
                  #include "file.h"
                  >
                  static const device_backend_ t mydevice_backen d = {
                  mydevice_read,
                  mydevice_write,
                  ...
                  };
                  >
                  static const device_backend_ t reefnet_sensusp ro_device_backe nd =
                  {...};
                  >
                  main and mydevice_read etc to follow.
                  That is essentially the same as what I wrote above, except that I'm not
                  using a header file. Because this is all "private" and used only inside
                  the c file. My header file contains only the "public" part of the api.

                  Comment

                  • Ian Collins

                    #10
                    Re: Forward declaration of static variable

                    Jef Driesen wrote:
                    Barry Schwarz wrote:
                    >On Sat, 23 Aug 2008 09:57:31 +0200, Jef Driesen
                    ><jefdriesen@ho tmail.com.inval idwrote:
                    >>
                    >>I have the following problem in a C project (but that also needs to
                    >>compile with a C++ compiler). I'm using a virtual function table, that
                    >>
                    >Do you mean you are writing a C++ program this will be used by a
                    >project that is mostly in C or do you need a program that compiles
                    >correctly in both? I will assume the latter. In spite of the
                    >similarity in the language names and a good deal of common syntax, the
                    >two are separate languages. Trying to write code that will compile in
                    >both will force you to limit yourself to the common subset and will
                    >also require you to make choices which are undesirable in at least one
                    >of the languages.
                    >
                    It's a C library. The reason why I would like to be able to compile it
                    with a C++ compiler is that I'm using a number of C99 features (variable
                    declarations anywhere in a code block). Unfortunately the msvc C
                    compiler does not support C99, but those features are supported in C++,
                    so I'm trying to make it build in C++ mode.
                    >
                    So it's now a C++ library, so you may as well update the code accordingly.

                    --
                    Ian Collins.

                    Comment

                    • Barry Schwarz

                      #11
                      Re: Forward declaration of static variable

                      On Mon, 25 Aug 2008 10:02:02 +0200, Jef Driesen
                      <jefdriesen@hot mail.com.invali dwrote:
                      >Barry Schwarz wrote:
                      >On Sat, 23 Aug 2008 09:57:31 +0200, Jef Driesen
                      ><jefdriesen@ho tmail.com.inval idwrote:
                      >>
                      >>I have the following problem in a C project (but that also needs to
                      >>compile with a C++ compiler). I'm using a virtual function table, that
                      snip
                      >>Now when I want to implement a new backend, I write the necessary
                      >>functions in the source file:
                      >>>
                      >>int mydevice_read (device_t *device, /* parameters */)
                      >>{
                      >> ...
                      >>}
                      >>>
                      >>int mydevice_write (device_t *device, /* parameters */)
                      >>{
                      >> ...
                      >>}
                      >>>
                      >>static const device_backend_ t mydevice_backen d = {
                      >> mydevice_read,
                      >> mydevice_write,
                      >> ...
                      >>};
                      >>>
                      >>So far no problem, but in a number of those functions, I need to have
                      >>access to the "mydevice_backe nd" variable. For instance to check whether
                      >>the backend pointer is the correct one. How can I forward declare this
                      >>variable properly?
                      >>>
                      >>When I add
                      >>>
                      >>static const device_backend_ t reefnet_sensusp ro_device_backe nd;
                      >>>
                      >>to the top of my source file, it works with the gcc compiler, but I'm
                      >>not sure this is valid according to the C (or C++) standard. It
                      >>
                      snip
                      >I only have a declaration (without any initialization) at the top. The
                      >initializati on is done after the implementation of the mydevice_*
                      >functions. So the file looks like this:
                      >
                      >static const device_backend_ t mydevice_backen d;
                      This is a definition because static object have an implied
                      initialization if one is not provided.
                      >
                      >int mydevice_read (device_t *device, /* parameters */)
                      >{
                      ...
                      >}
                      >
                      >int mydevice_write (device_t *device, /* parameters */)
                      >{
                      ...
                      >}
                      >
                      >static const device_backend_ t mydevice_backen d = {
                      mydevice_read,
                      mydevice_write,
                      ...
                      >};
                      And then this very obviously is a duplicate definition.
                      >
                      >With "moving to the top", I meant forward declaring the functions at the
                      >top of the file, so the initialization can be done at the top as well.
                      >Now will look like this:
                      >
                      >int mydevice_read (device_t *device, /* parameters */);
                      >int mydevice_write (device_t *device, /* parameters */);
                      >
                      >static const device_backend_ t mydevice_backen d = {
                      mydevice_read,
                      mydevice_write,
                      ...
                      >};
                      >
                      >int mydevice_read (device_t *device, /* parameters */)
                      >{
                      ...
                      >}
                      >
                      >int mydevice_write (device_t *device, /* parameters */)
                      >{
                      ...
                      >}
                      >
                      >But in that case I have to forward declare every single function that is
                      >listed in the virtual function table, while all I need would be a
                      Yes. But it is a simple cut and paste since you can use the same
                      first line(s) from the definition for your prototype. Just add a
                      semicolon.
                      >forward declaration of the "mydevice_backe nd" variable.
                      There is something called a tentative definition. I don't know if the
                      rules in C and C++ are sufficiently similar for it to be of value. I
                      also don't know if you can have a tentative definition for an object
                      with static duration.

                      --
                      Remove del for email

                      Comment

                      • jameskuyper@verizon.net

                        #12
                        Re: Forward declaration of static variable

                        Barry Schwarz wrote:
                        On Mon, 25 Aug 2008 10:02:02 +0200, Jef Driesen
                        <jefdriesen@hot mail.com.invali dwrote:
                        >
                        Barry Schwarz wrote:
                        On Sat, 23 Aug 2008 09:57:31 +0200, Jef Driesen
                        <jefdriesen@hot mail.com.invali dwrote:
                        >
                        >I have the following problem in a C project (but that also needs to
                        >compile with a C++ compiler). I'm using a virtual function table, that
                        ....
                        I only have a declaration (without any initialization) at the top. The
                        initialization is done after the implementation of the mydevice_*
                        functions. So the file looks like this:

                        static const device_backend_ t mydevice_backen d;
                        >
                        This is a definition because static object have an implied
                        initialization if one is not provided.
                        In C, because this is only a tentative definition, the initialization
                        is implicit only if there is no later non-tentative definition of the
                        same object with an explicit definition.
                        int mydevice_read (device_t *device, /* parameters */)
                        {
                        ...
                        }

                        int mydevice_write (device_t *device, /* parameters */)
                        {
                        ...
                        }

                        static const device_backend_ t mydevice_backen d = {
                        mydevice_read,
                        mydevice_write,
                        ...
                        };
                        >
                        And then this very obviously is a duplicate definition.
                        >

                        With "moving to the top", I meant forward declaring the functions at the
                        top of the file, so the initialization can be done at the top as well.
                        Now will look like this:

                        int mydevice_read (device_t *device, /* parameters */);
                        int mydevice_write (device_t *device, /* parameters */);

                        static const device_backend_ t mydevice_backen d = {
                        mydevice_read,
                        mydevice_write,
                        ...
                        };

                        int mydevice_read (device_t *device, /* parameters */)
                        {
                        ...
                        }

                        int mydevice_write (device_t *device, /* parameters */)
                        {
                        ...
                        }

                        But in that case I have to forward declare every single function that is
                        listed in the virtual function table, while all I need would be a
                        >
                        Yes. But it is a simple cut and paste since you can use the same
                        first line(s) from the definition for your prototype. Just add a
                        semicolon.
                        >
                        forward declaration of the "mydevice_backe nd" variable.
                        >
                        There is something called a tentative definition. I don't know if the
                        rules in C and C++ are sufficiently similar for it to be of value. I
                        also don't know if you can have a tentative definition for an object
                        with static duration.
                        "A declaration of an identifier for an object that has file scope
                        without an initializer, and without a storage-class specifier or with
                        the storage-class specifier static, constitutes a tentative
                        definition." (6.9.2p2)

                        As far as I can see, 'mydevice_backe nd" does have file scope, does not
                        have an (explicit) initializer, and the only strorage-class specifier
                        it has is "static", which is explicitly permitted. Therefore, it does
                        qualify as a tentative definition in C. As a result, it is perfectly
                        legal to follow it up with other tentative definitions, or with a non-
                        tentative definition. The different definitions must be of compatible,
                        as described in 6.2.7. Since device_backend_ t is typedef for a struct
                        type, about the only meaningful freedom allowed for the second
                        declaration to differ from the first is by providing an initializer.

                        The problem is that C++ has no such concept, so code which must
                        compile both as C code and as C++ code can't make use of that fact.

                        Comment

                        Working...