变体 1
您可以尝试使用联合。这将使接口“foo”依赖于 all 实现(这里:“bar”和“baz”)。优点是无需更改实现。
foo.h
#include "bar.h"
#include "baz.h"
typedef union {
Bar *bar;
Baz *baz;
} Foo;
Foo foo_create(void);
void foo_transmogrify(Foo f);
fooImplBar.c
#include "foo.h"
Foo foo_create(void)
{
Foo foo;
foo.bar = bar_create();
return foo;
}
void foo_transmogrify(Foo f)
{
bar_transmogrify(f.bar);
}
fooImplBaz.c
#include "foo.h"
Foo foo_create(void)
{
Foo foo;
foo.baz = baz_create();
return foo;
}
void foo_transmogrify(Foo f)
{
baz_transmogrify(f.baz);
}
您保留所有类型信息。
我在一个简单的项目中尝试过,但 Bar 和 Baz 在各自的标题中没有完全定义。它也应该适用于完整类型。
bar.h
typedef struct bar Bar;
Bar* bar_create(void);
void bar_transmogrify(Bar* f);
bar.c
#include <stdio.h>
#include <stdlib.h>
#include "bar.h"
typedef struct bar {
int i;
} Bar;
Bar* bar_create(void)
{
Bar* bar = malloc(sizeof (Bar));
bar->i = 23;
return bar;
}
void bar_transmogrify(Bar* f)
{
printf("Bar: %d\n", f->i);
}
baz.h
typedef struct baz Baz;
Baz* baz_create(void);
void baz_transmogrify(Baz* f);
baz.c
#include <stdio.h>
#include <stdlib.h>
#include "baz.h"
typedef struct baz {
float f;
} Baz;
Baz* baz_create(void)
{
Baz* baz = malloc(sizeof (Baz));
baz->f = 3.14159;
return baz;
}
void baz_transmogrify(Baz* f)
{
printf("Baz: %f\n", f->f);
}
main.c
#include "foo.h"
int main(void)
{
Foo f;
f = foo_create();
foo_transmogrify(f);
return 0;
}
是的,我知道,如果在某些严重的情况下使用此代码,则会出现内存泄漏。需要一些ba[rz]_destroy()。但这只是一个很容易解决的小问题。
编译过程如下:
gcc -Wall -Wextra -pedantic -c fooImplBar.c -o fooImplBar.o
gcc -Wall -Wextra -pedantic -c fooImplBaz.c -o fooImplBaz.o
gcc -Wall -Wextra -pedantic -c bar.c -o bar.o
gcc -Wall -Wextra -pedantic -c baz.c -o baz.o
gcc -Wall -Wextra -pedantic -c main.c -o main.o
gcc -Wall -Wextra -pedantic main.o fooImplBar.o bar.o -o mainImplBar
gcc -Wall -Wextra -pedantic main.o fooImplBaz.o baz.o -o mainImplBaz
变体 2:
每个实现都完成了未完全定义的结构。您可能需要调整您的实现,因为它需要使用相同的类型名称。
“foo.h”和你的一样。
fooImplBar.c
#include "foo.h"
#include "bar.h"
Foo* foo_create(void)
{
Foo* bar = bar_create();
return bar;
}
void foo_transmogrify(Foo* f)
{
bar_transmogrify(f);
}
fooImplBaz.c
#include "foo.h"
#include "baz.h"
Foo* foo_create(void)
{
Foo* baz = baz_create();
return baz;
}
void foo_transmogrify(Foo* f)
{
baz_transmogrify(f);
}
您保留类型信息,因为它是相同的类型。但是,每个实现都会以自己的方式定义类型。
bar.h
typedef struct foo {
int i;
} Foo;
Foo* bar_create(void);
void bar_transmogrify(Foo* f);
bar.c
#include <stdio.h>
#include <stdlib.h>
#include "bar.h"
Foo* bar_create(void)
{
Foo* bar = malloc(sizeof (Foo));
bar->i = 23;
return bar;
}
void bar_transmogrify(Foo* f)
{
printf("Bar: %d\n", f->i);
}
baz.h
typedef struct foo {
float f;
} Foo;
Foo* baz_create(void);
void baz_transmogrify(Foo* f);
baz.c
#include <stdio.h>
#include <stdlib.h>
#include "baz.h"
Foo* baz_create(void)
{
Foo* baz = malloc(sizeof (Foo));
baz->f = 3.14159;
return baz;
}
void baz_transmogrify(Foo* f)
{
printf("Baz: %f\n", f->f);
}
main.c
#include "foo.h"
int main(void)
{
Foo* f;
f = foo_create();
foo_transmogrify(f);
return 0;
}
编译就像变体 1 中一样。
如果我正确理解您的介绍,则不同的实现可能位于不同的文件夹中。然后,您可以将文件、类型和函数都命名为相同的名称,因为您不会在一个应用程序中使用多个。
这有点简单,但可能与您的设置不兼容。
这就是示例的外观。 “foo.h”和“main.c”是相同的。
bar/foo.c
#include <stdio.h>
#include <stdlib.h>
#include "../foo.h"
typedef struct foo {
int i;
} Foo;
Foo* foo_create(void)
{
Foo* foo = malloc(sizeof (Foo));
foo->i = 23;
return foo;
}
void foo_transmogrify(Foo* f)
{
printf("Bar: %d\n", f->i);
}
baz/foo.c
#include <stdio.h>
#include <stdlib.h>
#include "../foo.h"
typedef struct foo {
float f;
} Foo;
Foo* foo_create(void)
{
Foo* foo = malloc(sizeof (Foo));
foo->f = 3.14159;
return foo;
}
void foo_transmogrify(Foo* f)
{
printf("Baz: %f\n", f->f);
}
您不再需要包装器“fooImplBar”和“fooImplBaz”。
编译:
gcc -Wall -Wextra -pedantic -c bar/foo.c -o bar/foo.o
gcc -Wall -Wextra -pedantic -c baz/foo.c -o baz/foo.o
gcc -Wall -Wextra -pedantic -c main.c -o main.o
gcc -Wall -Wextra -pedantic main.o bar/foo.o -o mainBar
gcc -Wall -Wextra -pedantic main.o baz/foo.o -o mainBaz