Search code examples
c++cmacrosdecltype

C equivalent to C++ decltype


In my C project, there is a struct, created by another colleague, containing some function pointers:

struct tools {  
    int (*tool_a) (int, int, int);
    ...
};

I have no right to change this struct and relative files.

Now I'm coding with the struct.
I have to define a function, whose return type and list of arguments must be the same with the tools.tool_a.
Meaning that my function must be as below:

int my_func(int, int, int);

The problem is that the struct changes a lot, especially the return types, for example int is replaced by size_t today, so I have to change my code a lot.

I know that decltype in C++ can help me so I just want to know if C has something equivalent?

I'm thinking I may use macro but I don't know how, I even don't know if it's possible or not.

REAL CASE

I'm developing some testing tools for linux-kernel with C.
There have been many versions of custom kernels coming from other groups in my company. For historical reasons, some of them used int, others used size_t or ssize_t and so on.

Now when I code, I have to do like this:

// int my_func(int a, int b, int c)
size_t my_func(int a, int b, int c)
// ssize_t my_func(int a, int b, int c)
{}
struct tools my_tool = {
    .tool_a = my_func;
}

I have to keep commenting and uncommenting...


Solution

  • The sane solution is to enforce a typedef. If that isn't possible, and the number of alternative types the function could have are limited, as seems to be the case, you could cook up something with C11 _Generic.

    Instead of having a single function called my_func, create multiple functions with different names. Prefix their names depending on the return type. Then have a macro which in turn re-directs to the appropriate function, based on the type passed.

    Example:

    #include <stdio.h>
    
    /*** the struct that cannot be changed ***/
    struct tools {  
        int (*tool_a) (int, int, int);
    };
    
    /*** any number of functions with different types ***/
    int int_my_func(int a, int b, int c) 
    { 
      puts(__func__); 
    }
    
    size_t size_t_my_func(int a, int b, int c) 
    { 
      puts(__func__); 
    }
    
    /*** macro to select the appropriate function based on type ***/
    #define my_func_typeof(type)                           \
      _Generic( (type),                                    \
                int(*)(int,int,int)    : int_my_func,      \
                size_t(*)(int,int,int) : size_t_my_func)
    
    /*** caller code ***/
    int main (void)
    {
      struct tools my_tool = {
        .tool_a = my_func_typeof( (struct tools){0}.tool_a )
      };
    
      my_tool.tool_a(1,2,3);
    
    }
    

    Here I used a compound literal (struct tools){0}.tool_a to create a dummy object of the same type as tool_a, then passed that on to the macro which picks the appropriate function. If the type is not supported, there will be a compiler error since no matching _Generic association could be found.