The macro should be:
#define print(a,b) _Generic((b), int(*)[]: printfi, float(*)[]: printff)((a), (b))
the type of b is either int(*)[a] or float(*)[a], e.g. a pointer to an array of a int or float.
This code works for me:
#include <stdio.h>
void printff(int n,float m[n][n])
{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("\t%f",m[i][j]);
printf("\n");
}
}
void printfi(int n,int m[n][n])
{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("\t%d",m[i][j]);
printf("\n");
}
}
#define print(a,b) _Generic((b), int(*)[]: printfi, float(*)[]: printff)((a), (b))
int main()
{
float a[5][5];
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
a[i][j] = i * 5 + j;
print(5, a);
int b[2][2];
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
b[i][j] = i * 2 + j;
print(2, b);
}
https://godbolt.org/z/zrP9TnEcP
If you only use square 2D arrays, you can use this macro:
#define print(a) _Generic((a), int(*)[]: printfi, float(*)[]: printff)(sizeof *(a) / sizeof **(a), a)
It will calculate the length itself. Call it with print(a); or print(b);.
https://godbolt.org/z/xP918sn1s
It can be even easier when you use **(a) for the first parameter of _Generic:
#define print(a) _Generic(**(a), int: printfi, float: printff)(sizeof *(a) / sizeof **(a), (a))
https://godbolt.org/z/TzrY1G4ev