0

Say I have the following definitions for function pointers:

typedef void(*Tmp112HardwareInit)();
typedef void(*Tmp112HardwareDeInit)();
typedef bool(*Tmp112HardwareIsBusy)();

I have an interface object to hold instances of the above function pointers:

typedef struct
{
    Tmp112HardwareInit init;
    Tmp112HardwareDeInit deinit;
    Tmp112HardwareIsBusy is_busy;
} I2CInterface;

static I2CInterface _i2c_interface; // This is declared in module scope

Before accessing these function, I want to check if they've been assigned something. So instead of

_i2c_interface.init();

I want...

if (_i2c_interface.init) _i2c_interface.init();
else error = true;

I don't want to repeat these lines for each access of each variable in _i2c_interface, so I want to write a function:

bool _SensorTMP112_InterfaceInit()
{
    bool success = true;
    if (_i2c_interface.init)
    {
        _i2c_interface.init();
    }
    else
    {
        success = false;
    }

    return success;
}

Now, I don't want to write a function for each of these function pointers in _i2c_interface variable. I want a generic function, which will be called by other functions for each of these function pointers:

// Generic function
bool _SensorTMP112_InterfaceOperation(UnknownType fptr) // What should be UnknownType?
{
    bool success = true;
    if (fptr)
    {
        fptr();
    }
    else
    {
        success = false;
    }

    return success;
}

// Operation specific functions
bool _SensorTMP112_InterfaceInit()
{
    return _SensorTMP112_InterfaceOperation(_i2c_interface.init);
}

bool _SensorTMP112_InterfaceDeInit()
{
    return _SensorTMP112_InterfaceOperation(_i2c_interface.deinit);
}

bool _SensorTMP112_InterfaceIsBusy()
{
    return _SensorTMP112_InterfaceOperation(_i2c_interface.is_busy);
}

My question is what should be the type of UnknownType? Or is it even possible in standard C? Or is there any other way around for what I want to achieve? Not interested in non-standard solutions.

Donotalo
  • 12,748
  • 25
  • 83
  • 121
  • 4
    How would you expect to handle function with different numbers and/or types of arguments? What about functions with different return types? – dbush Dec 19 '19 at 15:42
  • 6
    On an unrelated note, names beginning with a single underscore and followed by an upper-case letter (like for example `_SensorTMP112_InterfaceInit`) are reserved by the C specification, and you should not declare or define such names yourself. See e.g. [this old answer](https://stackoverflow.com/a/8093406/440558) for a quote from the specification. It also tells you that you can't use any symbols beginning with underscore outside of functions (what you seem to call "module" scope). – Some programmer dude Dec 19 '19 at 15:43
  • A preprocessor macro would be good for that. – Matthieu Dec 19 '19 at 15:44
  • @dbush: Good catch. Haven't thought about it. – Donotalo Dec 19 '19 at 15:53
  • @Someprogrammerdude: Thanks. Didn't know that. – Donotalo Dec 19 '19 at 15:54
  • You could define an “enhanced function pointer” as `typedef struct { void (*PointerToFunction)(void); enum OtherInformation Information; } EnhancedFunctionPointer;`, where `Information` contains information about the actual pointer type (not necessarily `enum OtherInformation`; define it to suit your needs). Then various code in your program can pass around the `EnhancedFunctionPointer` type without regard to what type of function it is pointing to, while routines like the interface-operation routine use the `Information` member to do the necessary casts correctly. – Eric Postpischil Dec 19 '19 at 15:56

1 Answers1

2

Quick'n'dirty preprocessor macro:

#define callfn(f) if(f) f(); else result = false

Then

callfn(_i2c_interface.init);
result = true;
callfn(_i2c_interface.deinit);

(when bool success is earlier defined), or use it in functions:

bool _SensorTMP112_InterfaceInit()
{
    bool success = true;
    callfn(_i2c_interface.init);
    return success;
}

(You can also embed the bool success and return success inside the macro as well).

But you shouldn't expose that macro (i.e. #undef callfn after the functions bodies calling it) because it leaves many open doors.

Matthieu
  • 2,736
  • 4
  • 57
  • 87