我正试图找出一种方法来使用嵌套的全局结构作为我的C库的一种API命名空间。
具体来说,我想公开一个Primary
'命名空间结构',它包含其他类似的结构(例如Primary.Secondary
),它们本身包含函数指针(Primary.Secondary.a_function()
)。 / p>
我已经抽象出以下(相对)简单的例子,我想做什么:
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
结构也不是编译时常量,因此在编译时不能存储在另一个结构中。我可以通过在运行时设置所有接口来解决这个问题,但是......这似乎是一个非常糟糕的解决方案。我正在寻找这个问题的任何替代解决方案,你的C-fu比我能提出的更多。
(注意:这与this question有关,但有很大不同,而且更具体一些。)
答案 0 :(得分:2)
你正在努力的事情是无法做到的;抱歉。这是一个简洁的例子:
#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
。这就是语言的运作方式!
答案 1 :(得分:2)
你的代码中有一些奇怪的符号 - 我把它们转换成更正统的形式。另外,作为一般规则,避免在名称中使用双下划线;在C ++中,这是绝对必要的。 您还需要使用指向嵌入式结构的指针 - 然后代码将运行:
//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:
#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:
#include "Primary.h"
struct Primary_struct Primary = {
.Secondary = &Primary_Secondary
};
//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:
#include "Primary.h"
int main () {
Primary.Secondary->a_function();
return 0;
}
这会产生:
run!
hide!
答案 2 :(得分:0)
我最终选择了运行时方法,至少目前是这样。我可能稍后尝试一种指针方法(由Jonathan Leffler建议),看看我是否最终得到了一个不那么复杂/更易于理解的代码库......但是现在这种方法很有效。
我使用clang
(和gcc
)的__attribute__((constructor))
扩展来在运行时设置结构的关系;使用main()
中的一些代码可以更方便地(但不那么干净)实现同样的目标。
我会提供更多解释,但这是凌晨4点......嘿。我花了一整天时间在这上面&gt;,&lt;
<强> 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");
}