Вариант 1
Вы можете попробовать использовать union . Это сделает интерфейс "foo" зависимым от всех реализаций (здесь: "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