4

I have a structure that contains several function pointers. The generic interface is made in the header file.

Header File

typedef struct
{
    void (*Start)(void);
    void (*ByteWrite)(uint8_t *pBuffer);        // Modifies I2C buffer
    uint8_t (*ByteRead)(uint8_t *pBuffer);
    void (*ArrayWrite)(uint8_t *pBuffer);
    uint8_t (*ArrayRead)(uint8_t *pBuffer);
    bool (*Busy)(void);
} sI2C_t;


extern const sI2C_t I2C0;
extern const sI2C_t I2C1;
extern const sI2C_t I2C2;

Then in the C file each of the function-pointers are implemented to satisfy the structure interface.

C File

static void I2C0_Start(void) { ... }
static void I2C0_ByteWrite(*uint8_t) { ... }
static uint8_t I2C0_ByteRead(*uint8_t) { ... }
static void I2C0_ArrayWrite(*uint8_t) { ... }
static uint8_t I2C_ArrayRead(*uint8_t) { ... }
static bool I2C_Busy(void) { ... }

const sI2C I2C0 =
{
    I2C0_Start,
    I2C0_ByteWrite,
    I2C0_ByteRead,
    I2C0_ArrayWrite,
    I2C0_ArrayRead,
    I2C0_Busy
};

// Code-block repeated for I2C1, I2C2, etc. (REDUNDANT!)

This makes it relatively easy to access functions specific to the I2C interface:

bool status;

I2C0.Start();
status = I2C1.Busy();
...

Although the function-pointers are basically the same for I2C0, I2C1, and I2C2, etc., I have to write out each of them individually for every new structure interface. Since this is redundant, is there a way for me to implement these function pointers only once?

Biff
  • 1,009
  • 3
  • 11
  • 20
  • This may be one of those scenarios where a macro would be a justifiable solution. That said, if you have `I2C0`, `I2C1`, etc. as variable names, it sounds like perhaps an array would be a better approach overall? – Oliver Charlesworth Mar 16 '13 at 23:57
  • As in `extern const sI2C_t I2C[MAX_NUM];`? The functions would still have to be defined for each one, correct? Can you give an example of how I would use the macro? – Biff Mar 17 '13 at 00:06
  • 1
    [X-Macros](http://stackoverflow.com/questions/6635851/real-world-use-of-x-macros/) to the rescue! – luser droog Mar 17 '13 at 00:13
  • Will X-Macros allow me to distinguish between I2C0/1/2? In the function pointers I will need to anticipate that. – Biff Mar 17 '13 at 00:27
  • `*uint8_t`? Are you sure you can dereference a typename in a parameter list? – autistic Mar 17 '13 at 00:43

2 Answers2

1

The standard solution is to pass the structure pointer as the first parameter to the function. I.e. instead of:

I2C0.Start();

you write:

I2C0.Start(&I2C0);

You can then add some extra fields to the structure to identify which one it is (e.g. if you have fixed hardware addresses for each I2C bus, you might have the hardware addresses in an extra field of the structure).

This is the normal C way to do the equivalent of C++ classes.

user9876
  • 10,954
  • 6
  • 44
  • 66
  • I did think of passing it in as a pointer but it seemed to me that because I distinguish between `I2C0/1/2` (e.g. `I2C0.Start()` or `I2C1.Start()`) it would have been possible to implicitly indicate which one it is. – Biff Mar 19 '13 at 15:26
0

You can write a constructor function. Example:

typedef struct{
     int    a;
     char   b;
}example;

void constructor (example *pointer_to_struct, int a_value, char b_value){
    pointer_to_struct->a = a_value;
    pointer_to_struct->b = b_value;   /*remember: if you have strings don't have any 
                                     assignments, since a string (like any other array) is a pointer to 
                                     its first element*/
}


int main (void){

    example ex_struct;
    constructor(&ex_struct, 10, 'C');

    return 0;
}

EDIT: you can also write a function who makes the sames assignments for each structure of your selected type. Example:

void constructor(structure *p){
     p->a = 10;
     p->b = 'C';
}
Acsor
  • 1,011
  • 2
  • 13
  • 26