#include <stdio.h>
#include <string.h>

static int hashfunc(int a, const char *b, size_t length)
{
    printf("hashfunc(%i, %.*s, %zu)\n", a, length, b, length);
    return 4;
}

// Вариант 1: "Мааам, у меня паттерн-матчинг!".

#define cat_12_(x, ...) x ## __VA_ARGS__
#define choose_2_(x, v, ...) v
#define choose_(p, ...) choose_2_(__VA_ARGS__, p,)
#define hash(a, b, c) hashfunc(a, b, choose_(c, cat_12_(hash_, c(b))))
#define hash_0 , -1+sizeof

static void test1(void)
{
    const char *foo = "abcdef";
    char *bar = "abcdef";

    hash(1, foo, strlen(foo)); // strlen
    hash(2, bar, strlen(bar)); // strlen
    hash(3, "abcdef", 0);      // sizeof

    // Ниработает: матчится только литерал 0.
    // hash(1, "abcdef", 0x00);

    // Ниработает: ограничения на склейку токенов.
    // hash(1, foo, +strlen(foo));
}

#undef hash

// Вариант 2: современный, хипстерский - по мере сил проверяется тип.

#define hash(a, b) _Generic((b), \
    const char[sizeof(b)]: hashfunc(a, b, sizeof(b) - 1),\
          char[sizeof(b)]: hashfunc(a, b, sizeof(b) - 1),\
    default:               hashfunc(a, b, strlen(b)))

static void test2(void)
{
    const char *foo = "abcdef";
    char *bar = "abcdef";
    char baz[] = "abcdef";

    hash(1, foo);      // strlen
    hash(2, bar);      // strlen
    hash(3, baz);      // sizeof
    hash(4, "abcdef"); // sizeof
}

int main(void)
{
    test1();
    test2();
}
