views:

167

answers:

1

I’m using a pair of global variables in one of my .c files, matched to a single extern declaration each in two different .h files (well, one .h file, preprocessed two ways). One is for public consumption, and one is for private use. Both are const variables.

I only want to initialize one of the variables in my .c file, and then assign the second variable to the same content. Here’s the relevant contents of the .c file at the moment:

struct List_methods const List = {
  .create         = List__create,
  .create_naughty = List__create_naughty,
  // …
};
struct List_methods const Paws__List = List;

… and the corresponding .h:

#if defined(EXTERNALIZE)
# define  List_methods  Paws__List_methods
# define  List          Paws__List
#endif

// …

struct List_methods {
  list  (*create)         (void);
  list  (*create_naughty) (void);
  // …
} const extern List;

#if defined(EXTERNALIZE)
# undef   List_methods  Paws__List_methods
# undef   List          Paws__List
#endif

The goal here, is to ensure that when the .h is included with EXTERNALIZE defined, the including file gains access to the Paws__List variable, extern’d to the definition in my .c file. However, if it’s included without that definition, they gain access to an extern’d List instead (which I intend to use in my internal files, and make available if the #includeer wants it).

However, the Paws__List = List assignment blows up in my compiler, with the following error:

Source/Paws.o/list/list.c:32:40: error: initializer element is not a
      compile-time constant
struct List_methods const Paws__List = List;
                                       ^~~~

I’m looking for any help I can get to make this work as described above (that is, to define two const names for the same struct in my .c file, such that one or the other can be referenced by the .h header.)

A: 

If i understand you correctly, you want to define an interface (vtable) and the implementation will vary depending on EXTERNALIZE:

I'd go that route:


/* header file */
/* define the interface */
typedef struct List_methods {
  list  (*create)         (void);
  list  (*create_naughty) (void);
  // …
} List_Methods;

const extern List_methods Paws_List; // note: double underscores are afaik not allowed
const extern List_methods Other_List; // take any name but List

#ifdef EXTERNALIZE
# define  List          Paws_List
#else
# define  List          Other_List
#end

The important thing is that the structures are of the same type else you cannot assign one to the other. Second I would't override a symbol with an alias. This only makes problems when you want to use both for example in your .c file.

quinmars
No, that’s backwards: I only want to expose *one* interface, but it’s a different interface depending on `EXTERNALIZE`.Specifically, most people building against my library will include `Paws.h`, which sets `EXTERNALIZE` and then includes the other headers from my library. That file sets up a struct that *contains* these other structs, like `Paws.List.…`. That means that `List` itself isn’t available under that name; instead, it is provided as `Paws__List`, which is then stored under the `Paws` struct.
elliottcable
However, *inside* my library, (and optionally, if people include my headers directly (individually) without going through the global `Paws.h`), when `.c` files are compiled alone, `List` is defined itself, as are all of my other namespaces; it’s the opposite of the above. This allows me to maintain two APIs: an internal API that consists of a bunch of `const` variables (`List`, `Numeric`, `String`, etc)… and an external one, where *everything* is safely stored under `Paws` (to avoid conflicts when people build against it.)
elliottcable
So, all that explained… the `List.h` file, the one described in the question, needs to either `extern` a `List` definition (when included into internal files), or `extern` a `Paws__List` definition (when included into `Paws.h`, which sets `EXTERNALIZE`… and then stores `Paws__List` and friends on an `extern`’d `Paws` variable).
elliottcable