views:

261

answers:

5

What are some of the best ways to manage redundant typedefs used for platform independence from multiple middleware (operating systems, protocol stacks) vendors in the C programming language.

e.g.:
target.h

/* inclusion lock etc */
typedef char CHAR;
typedef unsigned char BYTE;
typedef unsigned short int WORD;
/* ... more of the same ... */

OS_types.h

/* inclusion lock etc */
typedef char CHAR;
typedef unsigned char BYTE;
typedef unsigned short int WORD;
/* ... more of the same ... */

At some point the compiler recognizes that it has two redundant typedef symbols and bails out with an error because this is simply not allowed by definition in C.

+1  A: 

That's a toughie. If I had to do something, I'd probably hold my nose and modify the third-party header-files -- possibly using macros to obtain conditional compilation of the offending typedefs.

Good luck.

Steve Emmerson
A: 

One approach, although it could be a lot of work, is to build your own "wrapper" layers which provide only the functionality you need from each of the middleware vendors. If you keep each wrapper in its own compilation unit (.c file) that's the only place you'll need to refer to the vendor's header file. That gives you a way to prevent the conflicting types from "leaking" into your application, as you can use your own typedefs and translate them to the vendor-specific types in the wrapper.

As Steve suggested, modifying the header files might be the best solution, depending on how often the vendor ships new versions of their stuff. The overhead could get pretty high.

Anodyne
+3  A: 

One possible way to do this without modifying the vendor's header would be to use the preprocessor with some header wrappers, e.g.

mytypes.h

#define BYTE VENDOR1_BYTE
#include <vendor1/types.h>
#undef BYTE

#define BYTE VENDOR2_BYTE
#include <vendor2/types.h>
#undef BYTE

typedef unsigned char BYTE;

This would result in the vendor's code generating different typedefs but hopefully mapped to the same actual type (unsigned char in the example). If the vendors are using different underlying types for the same type names then the method will likely not work.

quietbob
A: 

If you have the option to use C++ compilation for your own code (even if it is essentially C code) you could create namespace wrappers thus:

vendorA_target.h

namespace vendorA
{
    extern "C"
    {
        #include <target.h>
    }
}

vendorB_OS_types.h

namespace vendorB
{
    extern "C"
    {
        #include <target.h>
    }
}

Then in your own code. include these headers in place of the originals, and use scope-resolution, or if you are certain that types with the same name have identical or compatible definitions, simply us a using directive:

using vendorB::WORD
WORD timeout = 100 ;

vendorA::WORD x = 0xffff ;

Note that the extern "C" wrappers are not necessary if the headers already have them internally in __cplusplus macro conditionals - but it won't hurt.

Using C++ to compile C code imposes no overhead, but it does have stricter type comformaty checking, which while good for your code quality, may cause other headaches; especially if the third-party headers contain code that is invalid as C++. If the headers already have extern "C" declarations in __cplusplus macro conditionals, then they are already intended to be "C++-ready" and you may not have any such problems.

Unfortunately this method will not solve the problem of preprocessor macros with the same name. If you have that problem, you may have to #undef the macros from one header before including the other, or modify the headers.

Clifford
A: 

If the vendor is responsive to feedback, you could beg them to move those generic type definitions into a separate file, e.g. types.h. If they're isolated in a separate file, it's much easier to manage. The solution could be as simple as removing their types.h and adding your own project-specific types.h which can do whatever it needs to do in your project.

Even better, beg them to use the standard C typedefs in stdint.h, i.e. uint16_t.

Otherwise, I'd suggest a modification to the vendor header files, done as cleanly as possible so it's easy to re-do when they next release code. Of course this all goes in your VCS so you can track exactly what changes you made!

Craig McQueen