Include files with the same definitions

54 views
Skip to first unread message

Spyridon Metaxas

unread,
Jan 17, 2022, 5:15:13 PMJan 17
to
I have the following problem:

Within the same C executable I need to interact with two
different modules, A and B, that expose the same standardized API. Which
module is to be used is something to be decided at run time; for the
purposes of this discussion, it does not matter how or why.

In order to be able to interact with those modules I need to use
the include files IA and IAB, respectively, that they provide. I cannot
include them both, for they both define many of the same data structures
and function prototypes. However, because of proprietary extensions, each
defines stuff that is not present in the other. The thing is, at run time
I will need to be able to use such extensions: when the program is run I
will know whether A or B is to be used, and selecting what extension to
use will be easy.

The bottom line, I need to include both IA and IB at compile
time, but doing so would result in compile time errors.

How can one deal with this situation? I guess one could create a
new include file IC containing the stuff common to IA and IB, plus their
differences. However, that is a horrible hack fraught with danger, for,
among other things, there is no guarantee that bits that differ between
IA and IB will be compatible.

There has to be a better, more elegant way to deal with this.

Bart

unread,
Jan 17, 2022, 6:07:15 PMJan 17
to
On 17/01/2022 22:14, Spyridon Metaxas wrote:
> I have the following problem:
>
> Within the same C executable I need to interact with two
> different modules, A and B, that expose the same standardized API. Which
> module is to be used is something to be decided at run time; for the
> purposes of this discussion, it does not matter how or why.
>
> In order to be able to interact with those modules I need to use
> the include files IA and IAB, respectively, that they provide. I cannot
> include them both, for they both define many of the same data structures
> and function prototypes. However, because of proprietary extensions, each
> defines stuff that is not present in the other. The thing is, at run time
> I will need to be able to use such extensions: when the program is run I
> will know whether A or B is to be used, and selecting what extension to
> use will be easy.
>
> The bottom line, I need to include both IA and IB at compile
> time, but doing so would result in compile time errors.

But you can compile a program that includes either IA or IB? In that
case, what happens with the stuff that is missing because it's in the
other header; isn't it missed in the rest of the program, and cause errors?

> How can one deal with this situation? I guess one could create a
> new include file IC containing the stuff common to IA and IB, plus their
> differences. However, that is a horrible hack fraught with danger, for,
> among other things, there is no guarantee that bits that differ between
> IA and IB will be compatible.
>
> There has to be a better, more elegant way to deal with this.

You can provide two executables and a way to select which to run. Or
relegate the contents of A and B to external, shared libraries, then
provide both libraries. However the common parts have to be compatible
if there is one main executable.

Another way (I think Stefan Ram suggested this) is for both modules to
have a set of wrapper functions to provide a compatible interface to A
and B, then those functions form part of the shared libraries.

In might to be possible to have both statically linked into the one
executable, if they won't interfere with each other. But then access
might have to be through a set of function pointers set to either A
functions or B functions. It gets messy.

Yet another is to just compile when the program is 'run'; that is a
small program that determines which of A and B is needed, and compiles
the right modules, then invokes the executable. (Will the A/B choice be
done just once, or each time it's run?)

This can also get messy if your app is sprawling and needs a complex
build (the end user will need all the right tools as well). But if it
can be tidily contained, and you use a very small, very fast compiler
like Tiny C which works instantly, users may not even notice.


Lew Pitcher

unread,
Jan 17, 2022, 6:37:00 PMJan 17
to
Break the code that uses interface IA out into a separate source file,
and ensure that the source file #include's the definitions for interface
IA.

Do the same for the code that uses interface IB: break that code out into
it's own separate source file and ensure that the source file #include's
the definitions for interface IB.

Compile each of your main source file, the IA interface source and the IB
interface file separately. Then link the resulting object files together
with any support libraries that are necessary for proper execution.

--
Lew Pitcher
"In Skills, We Trust"

Andrey Tarasevich

unread,
Jan 17, 2022, 8:03:46 PMJan 17
to
On 1/17/2022 2:14 PM, Spyridon Metaxas wrote:
> Within the same C executable I need to interact with two
> different modules, A and B, that expose the same standardized API. Which

What is a "module" in this case? A dynamic library? A static library?
Just a bunch of source files? A single source file?

--
Best regards,
Andrey Tarasevich




James Kuyper

unread,
Jan 17, 2022, 8:07:11 PMJan 17
to
Is the problem only in the header files? If so, the solution is
relatively simple: have one file that #includes A.h, and have all code
that depends upon declarations from A.h in that file. Have a second file
that #includes B.h, and have all code that depends upon declarations
from B.h in that file. Those files should declare wrapper functions that
support the same interface to the rest of your code, hiding the
differences between A and B.

However, your wording left me wondering whether you might have
incorrectly expressed a problem that's actually harder to deal with. Is
it not just the headers, but also the corresponding object files, that
are incompatible in ways that prevent both of them from being linked
into the same program - do they declare functions or objects with
external linkage that have the same name? If so, you've got a much more
complicated problem to deal with.

Manfred

unread,
Jan 17, 2022, 11:47:23 PMJan 17
to
There is a contradiction in the problem exposition that might give some
hint about how to solve the problem:
You say A and B "expose the same standardized API", but IA.h and IB.h
are different and not compatible with each other, so they don't export
the same standardized API.
(Header files in C are pretty much the interface layer of their
respective modules)

You have to factor out the API that is really common between the two
(their MCD if you like), for example as James has suggested, and work
from there.

The second problem is about symbols: what do you mean by "standardized
API", is it e.g. a set of functions with the same names and signature or
signature only?
If you have a function foo in each module, with the same signature but
different body, you can't link them both in the same executable.

One solution that comes to mind would be using dynamic linking (.so in
*NIX or .DLL in Windows), but that's one step further.

Öö Tiib

unread,
Jan 18, 2022, 4:16:31 AMJan 18
to
Yes, the OP as quoted above said that modules "both define many of the
same data structures and function prototypes". Most likely "same" there
means on several cases "with same name" and not "with same name
and definition". As the identified pain point was about #including the
header files then that indicates desire to link both the "modules"
to same program. So there will be "many" one definition rule violations
if to attempt to link the modules into same program, several of what
are not simple to fix.

Therefore without capability to either rename half of the "many" or to
consolidate both halves of "many" under same, one definition the OP
can not link the modules into same program and so has perhaps to
use things like multiprocessing to solve the issue.

Richard Damon

unread,
Jan 18, 2022, 8:11:50 AMJan 18
to

On 1/17/22 5:14 PM, Spyridon Metaxas wrote:
Simple description:

If IA.h and IB.h both need a 'c' which is the SAME between the two of
them, it needs to be in a seperate include file IC.h

If IA.h and IB.h both need a 'd' which DIFFERS between the two of them,
you are out of luck, you can't have two different things with the same
global name.

Basically, when writing a reusable header, anything 'unique' to that
header needs to be put into some sort of locally allocated namespace
reserved for that header (and its associated code), and anything that it
needs to share in common with other stuff should be in a separate common
header defined for that purpose.

If you read the Standard, you will notice that it carefully defines what
symbols the implementation might use, and thus are not available for the
application. In the same way, a 'module' designer needs to carve out a
name space of symbols that they will reserve for themselves, and only
use those at the global level. Two modules that reserve the some of the
same symbols are not compatible with each other, unless that part of the
resservation is in a seperate header that they agree on.

For C, it is common to just add a short prefix to all names that is
hopefully unique.

james...@alumni.caltech.edu

unread,
Jan 18, 2022, 10:31:18 AMJan 18
to
On Tuesday, January 18, 2022 at 4:16:31 AM UTC-5, Öö Tiib wrote:
> On Tuesday, 18 January 2022 at 03:07:11 UTC+2, james...@alumni.caltech.edu wrote:
> > On 1/17/22 5:14 PM, Spyridon Metaxas wrote:
> > > I have the following problem:
> > >
> > > Within the same C executable I need to interact with two
> > > different modules, A and B, that expose the same standardized API. Which
> > > module is to be used is something to be decided at run time; for the
> > > purposes of this discussion, it does not matter how or why.
> > >
> > > In order to be able to interact with those modules I need to use
> > > the include files IA and IAB, respectively, that they provide. I cannot
> > > include them both, for they both define many of the same data structures
> > > and function prototypes.
...
> > However, your wording left me wondering whether you might have
> > incorrectly expressed a problem that's actually harder to deal with. Is
> > it not just the headers, but also the corresponding object files, that
> > are incompatible in ways that prevent both of them from being linked
> > into the same program - do they declare functions or objects with
> > external linkage that have the same name? If so, you've got a much more
> > complicated problem to deal with.
> Yes, the OP as quoted above said that modules "both define many of the
> same data structures and function prototypes". Most likely "same" there
> means on several cases "with same name" and not "with same name
> and definition" ...

I think that's definitely a possibility, but I don't think his description was
sufficiently clear to guarantee that he's facing this problem. Both headers might
define the same struct type, and provide two different declarations of the same
function, in addition to declaring additional identifiers that are unique to each
module. That's why I asked about it, rather than assuming one answer or the
other. That would be poor design: the shared features should be declared once
in a separate header file, with it's own header guards to prevent doubled
declarations. However, I'd seen worse examples of poor design, so I wouldn't
rule out that possibility.

Bonita Montero

unread,
Jan 18, 2022, 12:49:24 PMJan 18
to
That's easy to solve in C++ with inheritance.

Richard Damon

unread,
Jan 18, 2022, 8:47:34 PMJan 18
to
And yes, if you have two headers with conflicting declarations for the
same symbol, those headers are incompatible with each other so you can't
use both in the same program.

Sometimes, you just have to live with the fact that something wasn't
built in a way that allows it to be easily reused.

Hopefullly, they have the source for the modules (and the right
permissions) that use those headers, so they can be edited and made
compatible, or they can't use one of the modules.

That's life.

Vir Campestris

unread,
Jan 20, 2022, 4:20:09 PMJan 20
to
On 18/01/2022 17:49, Bonita Montero wrote:
> That's easy to solve in C++ with inheritance.

In C++ we could include the two .h files within namespaces.

But this isn't C++, so he's got to live within the language he's using.

Andy

Chris M. Thomasson

unread,
Jan 20, 2022, 8:02:00 PMJan 20
to
One pattern is something akin to:

common.h
impl_0.h
impl_1.h
impl.h

impl.h can select what impl_n.h header to import based on some sort of
macro. common.h is common to the various impl_n's... Also, think of
something really simple like:


void foo_version_0(void)
{

}

void foo_version_1(void)
{

}

void foo_version_2(void)
{

}

// API

#define foo_version foo_version_1

Cheap, and can work. There are many other ways to do these types of
things in C...
Reply all
Reply to author
Forward
0 new messages