Хранение глобальной переменной структуры внутри другой глобальной структуры в C - PullRequest
1 голос
/ 06 февраля 2010

Я пытаюсь найти способ использовать вложенные глобальные структуры в качестве своего рода пространства имен API для моей библиотеки C.

В частности, я хочу показать одну Primary ‘структуру пространства имен’, которая содержит другие такие структуры (например, Primary.Secondary), которые сами содержат указатели на функции (Primary.Secondary.a_function()).

Я абстрагировал следующий (относительно) простой пример того, что я хочу сделать:

main.c:

#include "Primary.h"

int main () {
  Primary.Secondary.a_function();
  return 0;
}

Primary.h:

#if !defined(SECONDARY_H)
# include "Secondary.h"
#endif

struct Primary_struct {
  struct Primary__Secondary_struct  Secondary;
} extern Primary;

Primary.c

#include "Primary.h"

struct Primary_struct Primary = {
  .Secondary = Primary__Secondary
};

Secondary.h:

struct Primary__Secondary_struct {
  void  (*a_function) (void);
  void  (*another_function) (void);
} extern Primary__Secondary;

Secondary.c

#include "Secondary.h"

#include <stdio.h>

void  Primary__Secondary__a_function  (void);
void  Primary__Secondary__another_function  (void);

struct Primary__Secondary_struct {
  .a_function       = Primary__Secondary__a_function,
  .another_function = Primary__Secondary__another_function
} extern Primary__Secondary;

void Primary__Secondary__a_function(void) {
  Primary.Secondary.another_function();
}

void Primary__Secondary__another_function(void) {
  printf("run!\n");
}

Когда я пытаюсь скомпилировать это, я сталкиваюсь со следующей ошибкой компилятора:

 > C -O0 Primary.c Secondary.c main.c
Primary.c:3:33: error: initializer element is not a compile-time constant
struct Primary_struct Primary = {
                                ^
1 diagnostic generated.

Следует отметить, что в идеале переменные Primary и Primary__Secondary должны быть const. Я волновался, что дополнительная сложность усугубит проблему ... так что пока я оставил этот аспект вне себя.

Проблема, по-видимому, заключается в том, что по какой-то причине, даже если она установлена ​​как const и содержит только элементы, присутствующие во время компиляции, структура Primary__Secondary не является константой времени компиляции и, следовательно, не может быть сохранена другая структура во время компиляции. Вероятно, я могу обойти это, настроив все интерфейсы во время выполнения, но ... это выглядит по-настоящему хакерским решением. Я ищу какие-то альтернативные решения этой проблемы, чтобы вы могли придумать больше, чем я могу.

( Примечание : Это относится к этому вопросу , но существенно отличается и немного более конкретен.)

Ответы [ 3 ]

2 голосов
/ 06 февраля 2010

У вас были некоторые странные записи в вашем коде - я преобразовал их в более ортодоксальную форму. Также, как правило, избегайте использования двойного подчеркивания в именах; в C ++ это абсолютно необходимо. Вам также нужно использовать указатель на встроенную структуру - тогда код запустится:

Primary.h

//Primary.h:
#ifndef PRIMARY_H
#define PRIMARY_H

#include "Secondary.h"

struct Primary_struct {
  struct Primary_Secondary_struct *Secondary;
};

extern struct Primary_struct Primary;

#endif // PRIMARY_H

Secondary.h

//Secondary.h:
#ifndef SECONDARY_H
#define SECONDARY_H

struct Primary_Secondary_struct {
  void  (*a_function)(void);
  void  (*another_function)(void);
};

extern struct Primary_Secondary_struct Primary_Secondary;

#endif // SECONDARY_H

Primary.c

//Primary.c:

#include "Primary.h"

struct Primary_struct Primary = {
  .Secondary = &Primary_Secondary
};

Secondary.c

//Secondary.c:

#include "Secondary.h"
#include "Primary.h"
#include <stdio.h>

void Primary_Secondary_a_function(void);
void Primary_Secondary_another_function(void);

struct Primary_Secondary_struct Primary_Secondary = {
  .a_function       = Primary_Secondary_a_function,
  .another_function = Primary_Secondary_another_function
};

void Primary_Secondary_a_function(void) {
  Primary_Secondary.another_function();
  printf("hide!\n");
}

void Primary_Secondary_another_function(void) {
  printf("run!\n");
}

main.c

//main.c:
#include "Primary.h"

int main () {
  Primary.Secondary->a_function();
  return 0;
}

Создает:

run!
hide!
2 голосов
/ 06 февраля 2010

То, что вы пытаетесь, не может быть сделано; извиняюсь. Вот сжатый пример:

#include <stdio.h>

int a = 5;
int b = a;

int main(int argc, char *argv[])
{
  printf("Hello, world!\n"); 
  return 0;
}

Компиляция этого кода дает ошибку:

main.c:4: error: initializer element is not constant

Поскольку компилятор не знает, как сделать присваивание int b = a во время компиляции. Так работает язык!

0 голосов
/ 06 февраля 2010

Я закончил с подходом во время выполнения, по крайней мере, на данный момент. Позже я мог бы попробовать подход указателей (предложенный Джонатаном Леффлером выше) и посмотреть, не получится ли у меня менее сложная / более понятная кодовая база… но пока это работает.

Я использую clanggcc) расширение __attribute__((constructor)) для настройки отношений структур во время выполнения; то же самое может быть достигнуто более переносимо (но менее чисто) с помощью некоторого кода в main().

Я бы предложил немного больше объяснений, но здесь уже 4 утра ... хе. Я провел весь день на этом>, <</p>

main.c:

#include "Package.h"

int main () {
  Package.One.a_function();
  Package.One.another_function();

  Package.Two.a_function();
  Package.Two.another_function();

  return 0;
}

Package.h:

#define PACKAGE_H

#if !defined(ONE_H)
# include "One.h"
#endif
#if !defined(TWO_H)
# include "Two.h"
#endif

// It seems this is broken, at least in `clang`
// #if __has_feature(attribute_constructor)
# define constructor __attribute__((constructor))
// #endif

struct Package_struct {
  struct Package__One_struct  One;
  struct Package__Two_struct  Two;
};

struct Package_struct extern Package;

Package.c

#include "Package.h"

struct Package_struct Package = {};

One.h

#define ONE_H

struct Package__One_struct {
  void  (*a_function)       (void);
  void  (*another_function) (void);
};

struct Package__One_struct extern Package__One;

One.c

#include "One.h"
#include "Package.h"

#include <stdio.h>

void  Package__One__a_function        (void);
void  Package__One__another_function  (void);

struct Package__One_struct Package__One = {
  .a_function       = Package__One__a_function,
  .another_function = Package__One__another_function
};
void constructor Package__register_One(void) {
  Package.One = Package__One; }

void Package__One__a_function(void) {

  Package.One.another_function();

}

void Package__One__another_function(void) {

  printf("one!\n");

}

Two.h

#define TWO_H

struct Package__Two_struct {
  void  (*a_function)       (void);
  void  (*another_function) (void);
};

struct Package__Two_struct extern Package__Two;

Two.c:

#include "Two.h"
#include "Package.h"

#include <stdio.h>

void  Package__Two__a_function        (void);
void  Package__Two__another_function  (void);

struct Package__Two_struct Package__Two = {
  .a_function       = Package__Two__a_function,
  .another_function = Package__Two__another_function
};
void constructor Package__register_Two(void) {
  Package.Two = Package__Two; }

void Package__Two__a_function(void) {

  Package.Two.another_function();

}

void Package__Two__another_function(void) {

  printf("two!\n");

}
...