I am trying to create a portable API in ANSI C89 / ISO C90 to access a wireless network device on a serial interface. The library will have several network levels, and different versions should be run on embedded devices with a size of no more than 8 bits with 32 KB of code and 2 thousand. Data on embedded devices with a megabyte or more of code and data.
In most cases, the target processor will have one network interface, and I want to use one global structure with all the status information for this device. I do not want to pass a pointer to this structure through network layers.
In several cases (for example, a device with a large number of resources that must live in two networks) I will interact with several devices, each with its own global state, and it will need to pass a pointer to this state (or an index to the state array) through layers.
I came up with two possible solutions, but none of them are very good. Keep in mind that a full driver will be 20,000 lines or more, span multiple files and contain hundreds of functions.
The first solution requires a macro that discards the first parameter for each function that should access the global state:
typedef struct dev_t {
int var;
long othervar;
char name[20];
} dev_t;
#ifdef IF_MULTI
#define foo_function( x, a, b, c) _foo_function( x, a, b, c)
#define bar_function( x) _bar_function( x)
#else
extern dev_t DEV;
#define IFACE (&DEV)
#define foo_function( x, a, b, c) _foo_function( a, b, c)
#define bar_function( x) _bar_function( )
#endif
int bar_function( dev_t *IFACE);
int foo_function( dev_t *IFACE, int a, long b, char *c);
#ifndef IF_MULTI
dev_t DEV;
#endif
int bar_function( dev_t *IFACE)
{
memset( IFACE, 0, sizeof *IFACE);
return 0;
}
int foo_function( dev_t *IFACE, int a, long b, char *c)
{
bar_function( IFACE);
IFACE->var = a;
IFACE->othervar = b;
strcpy( IFACE->name, c);
return 0;
}
The second solution defines macros for use in function declarations:
typedef struct dev_t {
int var;
long othervar;
char name[20];
} dev_t;
#ifdef IF_MULTI
#define DEV_PARAM_ONLY dev_t *IFACE
#define DEV_PARAM DEV_PARAM_ONLY,
#else
extern dev_t DEV;
#define IFACE (&DEV)
#define DEV_PARAM_ONLY void
#define DEV_PARAM
#endif
int bar_function( DEV_PARAM_ONLY);
int foo_function( DEV_PARAM int a, long b, char *c);
#ifndef IF_MULTI
dev_t DEV;
#endif
int bar_function( DEV_PARAM_ONLY)
{
memset( IFACE, 0, sizeof *IFACE);
return 0;
}
int foo_function( DEV_PARAM int a, long b, char *c)
{
bar_function( IFACE);
IFACE->var = a;
IFACE->othervar = b;
strcpy( IFACE->name, c);
return 0;
}
The C code for accessing any method remains the same:
#define IF_MULTI
#include "network.h"
dev_t if0, if1;
int main()
{
foo_function( &if0, -1, 3.1415926, "public");
foo_function( &if1, 42, 3.1415926, "private");
return 0;
}
#include "network.h"
int main()
{
foo_function( 11, 1.0, "network");
return 0;
}
, ? , , , - . , "_", .
" ", , , "" , . , , .
? ? - ?
( , ++ , ++.)