Is it possible to "unstringify" __func__ in C?

Viewed 182

I'm trying to write Vulkan function wrapper macro that "generates" a typename of the style PFN_vkCurrentFunction automatically.

Pseudo-code example (doesn't compile):

#define CALL(...)                                 \
  PFN_##__func__ functionPtr                      \
    = (PFN_##__func__) GetProcAddress(__func__);  \
  functionPtr( __VA_ARGS__ );

VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
  const VkInstanceCreateInfo*                 pCreateInfo,
  const VkAllocationCallbacks*                pAllocator,
  VkInstance*                                 pInstance)
{
  CALL( pCreateInfo, pAllocator, pInstance );
}

The PFN_##__func__ part of this macro is invalid and will not compile.

3 Answers

Is it possible to “unstringify” __func__ in C?

No, it's not possible. C doesn't have reflection and __func__ is not a macro, but it appears as-if declared by a static const char __func__[] declaration.

I would go with encompassing the whole function definition:

#define CALL(NAME, ...)                                 \
  PFN_##NAME functionPtr                      \
    = (PFN_##NAME) GetProcAddress(NAME);  \
  functionPtr( __VA_ARGS__ );

#define CALL_DECL_6(ret, name, _1, _2, _3, _4, _5, _6) \
ret name(_1 _2, _3 _4, _5 _6) { \
    CALL(name, _2, _4, _6); \
}
#define CALL_DECL_N(_9,_8,_7,_6,_5,_4,_3,_2,_1,N,...) CALL_DECL_##N
#define CALL_DECL(ret, name, ...)  \
        CALL_DECL_N(__VA_ARGS__,9,8,7,6,5,4,3,2,1)(ret, name, __VA_ARGS__)

CALL_DECL(
   VKAPI_ATTR VkResult VKAPI_CALL, vkCreateInstance,
      const VkInstanceCreateInfo *, pCreateInfo,
      const VkAllocationCallbacks *, pAllocator,
      VkInstance *, pInstance
)

As a workaround, I can add an argument at the start and stringify it. But I'm not satisfied with this solution, because I need to write out vkCreateInstance twice:

#define STR(entry) #entry
#define CALL(entry, ...)                        \
  PFN_##entry functionPtr                       \
    = (PFN_##entry) GetProcAddress(STR(entry)); \
  functionPtr( __VA_ARGS__ );

VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
  const VkInstanceCreateInfo*                 pCreateInfo,
  const VkAllocationCallbacks*                pAllocator,
  VkInstance*                                 pInstance)
{
  CALL( vkCreateInstance, pCreateInfo, pAllocator, pInstance );
}

Is it possible to “unstringify” __func__ in C?

This is not possible in standard C.

Read for example the C11 standard draft n1570, or the Modern C book, and see this website about C.

but POSIX like operating systems (e.g. Linux) have dlopen and dlsym

So read dlopen(3) and dlsym(3) (and also, on Linux proc(5) and Advanced Linux Programming). Look into my manydl.c example.

So perhaps try something inspired from

/// untested code...
void* progdlh = dlopen(NULL, RTLD_NOW);
if (!progdlh) {
  fputs(dlerror(), stderr);
  exit(EXIT_FAILURE);
};
void* funad = dlsym(progdlh, "some_function_name");
if (!funad) {
  fputs(dlerror(), stderr);
  exit(EXIT_FAILURE);
}
VkAllocationCallbacks* cb = (VKAllocationCallBacks*)funad;

Consider also using machine code generation libraries such as GNU lightning or libgccjit or asmjit or luajit. You might generate some machine code at runtime (like SBCL does) to call your Vulkan code.

You could also generate some C code at runtime in /tmp/generated.c, and use tinycc or fork(2) (e.g. with popen(3) or system(3)...) a process running gcc -fPIC -shared -O /tmp/generated.c -o /tmp/generated-plugin.so then dlopen that /tmp/generated-plugin.so. This has been done in the CHARIOT and DECODER projects.

I took a Linux centered point of view. For Windows, study the WinAPI.

Related