dimanche 25 octobre 2020

How to create weak alias default definition for interface function with multiple implementations

Objective

  • Create a generic interface with default implementations of each function pointer used in the interface.
    • This is desired in part so that we never have a null pointer reference when using an interface function pointer.
  • Support multiple "instances" of this interface (particularly for different implementations of this interface).
    • This means that we should be able to create generic interface instance of type A and a generic interface instance of type B where either instance may have function pointers using default definitions.

Result

I am using weak aliases for the default implementations however it seems as though this does not allow me to have multiple implementations of my interface and when I try to compile them in either I get static declaration follows non-static declaration errors. Removing the static keyword results in multiple definition errors.

Example code

My interface, specific and default implementation can be simplified to the following example.

dfltDef_Header.h

#ifndef __DEFAULTDEF_H_
#define __DEFAULTDEF_H_
#include <stdint.h>
#include <stdbool.h>
#define _weak_alias(old, new) \
        extern __typeof(old) new __attribute__((weak, alias(#old)))

typedef struct {
    int  (*getVal)(void);
    bool (*isTrue)(void);
} myIF_t;

int getVal(void);
bool isTrue(void);

#endif // __DEFAULTDEF_H_

dfltDef_impl.c

#include <stdint.h>
#include <stdbool.h>
#include "dfltDef_header.h"

bool dflt_isTrue(void) {
    return true;
}

int dflt_getVal(void) {
    return 3;
}

_weak_alias(dflt_isTrue, isTrue);

_weak_alias(dflt_getVal, getVal);

someInterfaceImpl.h

#ifndef __SOMEINTERFACEIMPL_H_
#define __SOMEINTERFACEIMPL_H_
#include "dfltDef_header.h"

myIF_t *getInterface(void);

#endif // __SOMEINTERFACEIMPL_H_

someInterfaceImpl.c

#include "someInterfaceImpl.h"
#include "dfltDef_header.h"

bool isTrue(void) {
    return false;
}

static myIF_t thisInterface = {
    .getVal = getVal,
    .isTrue = isTrue,
};

myIF_t *getInterface(void) {
    return &thisInterface;
}

anotherInterfaceImpl.h

#ifndef __ANOTHERINTERFACEIMPL_H_
#define __ANOTHERINTERFACEIMPL_H_
#include "dfltDef_header.h"

myIF_t *getOtherInterface(void);
#endif // __ANOTHERINTERFACEIMPL_H_

anotherInterfaceImpl.c

#include "anotherInterfaceImpl.h"
#include "dfltDef_header.h"

static int getVal(void) {
    return 1;
}

static myIF_t thisInterface = {
    .getVal = getVal,
    .isTrue = isTrue,
};

myIF_t *getOtherInterface(void) {
    return &thisInterface;
}

dflDef_App.c

#include "dfltDef_header.h"
#include "someInterfaceImpl.h"
#include "anotherInterfaceImpl.h"

int main() {
    /* DFLT_FUNC(getVal) */
    myIF_t *IF = getInterface();
    printf("%d %d\n", IF->isTrue(), IF->getVal());

    myIF_t *otherIF = getOtherInterface();
    printf("%d %d\n", otherIF->isTrue(), otherIF->getVal());

    return 0;
}

When compiled with

gcc dflDef_App.c someInterfaceImpl.c anotherInterfaceImpl.c dfltDef_impl.c -o dfltExample

I get the following:

anotherInterfaceImpl.c:4:12: error: static declaration of ‘getVal’ follows non-static declaration
    4 | static int getVal(void) {
      |            ^~~~~~
In file included from anotherInterfaceImpl.h:3,
                 from anotherInterfaceImpl.c:1:
dfltDef_header.h:13:5: note: previous declaration of ‘getVal’ was here
   13 | int getVal(void);
      |     ^~~~~~

Key questions

  • Is there a way to use static function definitions to override weak aliases?
  • Can I make one strong symbol hidden from the others (via static libraries or otherwise)?
  • Is this simply not possible or bad practice ?

It would be great to do this in such a way that the interface function definitions can only be used via the interface and if non is defined then we fall back on the default definition. Any and all help/advise is much appreciated.

Aucun commentaire:

Enregistrer un commentaire