Enquanto aprendia sobre como as macros funcionam, tentei definir uma macro que funcionasse com diferentes tipos de dados sem ter que definir vários tipos. Eu costumava _Generic
tornar essa tarefa mais fácil. No entanto, depois que não funcionou, mesmo depois de fazer alterações várias vezes, pedi ao deepseek para descobrir, o que eventualmente resultou nisso:
#define FOO(var) _Generic((var), \
int: printf(#var " = %d\n", (int)(var)), \
double: printf(#var " = %lf\n", (double)(var)), \
long: printf(#var " = %ld\n", (long)(var)), \
char: printf(#var " = '%c'\n", (char)(var)), \
float: printf(#var " = %f\n", (float)(var)), \
default:printf(#var " = unknown type\n"))
int main(void) {
int a = 3;
FOO(a); // correctly prints "a = 3"
}
Em outros exemplos de código na referência cpp e no SO, nunca vi ninguém tendo que fazer typecast para fazer isso funcionar. Remover os typecasts ( int: printf(#var " = %d\n",(var)), \
...) mostra um aviso "O formato especifica o tipo 'long', mas o argumento tem o tipo 'int'" e fornece um aviso de compilação ( -Wall
habilitado):
ue_05.c: In function ‘main’:
ue_05.c:47:14: warning: format ‘%lf’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
47 | FOO(a);
| ^
ue_05.c:27:25: note: in definition of macro ‘FOO’
27 | double: printf(#var " = %lf\n", (var)), \
| ^~~
ue_05.c:47:14: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
47 | FOO(a);
| ^
ue_05.c:28:25: note: in definition of macro ‘FOO’
28 | long: printf(#var " = %ld\n", (var)), \
| ^~~
ue_05.c:47:14: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
47 | FOO(a);
| ^
ue_05.c:30:25: note: in definition of macro ‘FOO’
30 | float: printf(#var " = %f\n", (var)), \
Não consegui descobrir por que o typecast é necessário aqui e o deepseek também não conseguiu esclarecer as coisas.
Por que o typecast é necessário aqui e onde ele está documentado?