0

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.

Acorn
  • 24,970
  • 5
  • 40
  • 69
Nick
  • 260
  • 3
  • 11
  • AFAIK, inlining by link-time optimization is entirely independent of the compile-time inlining requested by the `inline` keyword, and the latter inherently requires that the code of the function be contained in (or included into) the translation unit being compiled. – Nate Eldredge Aug 06 '20 at 19:15
  • You can't inline a function that uses an opaque pointer if the function dereferences that pointer in any way. If you could, the pointer would no longer be opaque. – Andrew Henle Aug 06 '20 at 19:22

2 Answers2

1

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.

Acorn
  • 24,970
  • 5
  • 40
  • 69
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.

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157