How to correctly define inline functions that handle opaque pointers?

237 Views Asked by At

How do I correctly define an inline function that dereferences an opaque pointer according to the C99 standard? Let's say I've organized a program in three files:

opaq.h:

typedef struct Opaq Opaq;

Opaq* opaq_init(void* ptr, int size);
void opaq_free(Opaq* o);
inline int opaq_size(Opaq* o);

opaq.c:

#include <stdlib.h>
#include "opaq.h"

struct Opaq {
    void* ptr;
    int size;
};

Opaq* opaq_init(void* ptr, int size)
{
    Opaq* o = malloc(sizeof(*o));

    o->ptr = ptr;
    o->size = size;

    return o;
}

void opaq_free(Opaq* o)
{
    free(o);
}

int opaq_size(Opaq* o)
{
    return o->size;
}

main.c:

#include <stdlib.h>
#include "opaq.h"

int main(void)

{
    Opaq* o;
    int size;

    o = opaq_init(NULL, 3);
    size = opaq_size(o);
    opaq_free(o);

    return 0;
}

I would like opaq_size to be inlined in main.c. Such inlining is possible to my knowledge as inlining can occur during linkage. However, trying to compile this with GCC gives the following warning:

$ gcc -Winline -o main main.c opaq.c
In file included from main.c:2:0:
opaq.h:5:12: warning: inline function ‘opaq_size’ declared but never defined
 inline int opaq_size(Opaq* o);

Using the keyword extern in opaq.h gives the same warning. Compiling with -fgnu89-inline resolves the warning, however disassembling main reveals that inlining did not actually occur. Notice I cannot define the function in the header (as static inline), as the structure definition is out of scope.

2

There are 2 best solutions below

0
Acorn On

Such inlining is possible to my knowledge as inlining can occur during linkage.

No, a compiler cannot inline something it doesn't know about. A classical linker cannot do it either because the object files are already compiled.

The point of an opaque pointer is to make translation units independent of the type behind the pointer (usually to offer an stable ABI to clients), so it is not clear what you are trying to accomplish. If you inline in any way, including things like LTO (Link-Time Optimization), they won't be independent anymore.

In summary, do not use an opaque pointer if you don't need the guarantees it provides.

0
John Bollinger On

I would like opaq_size to be inlined in main.c. Such inlining is possible to my knowledge as inlining can occur during linkage.

Yes and no. C has no way to require inlining under any circumstances. In particular, the inline keyword is not specified to have that effect -- it serves as a hint, not a directive. The inline keyword places other requirements, however, that are not compatible with opaque types. Specifically, if a function is declared inline in a particular translation unit, then an inline definition of that function must also appear in the TU. You cannot satisfy that requirement if the function in question must manipulate an object whose type is opaque to the TU.

If your C implementation is capable of link-time inlining then turn on any options needed to enable that. If it offers options or language extensions for requesting that such inlining be performed on specific functions, then use them. The result you want is dependent on implementation-specific behavior, and it may or may not be available to you in the particular implementation you have chosen.