admin管理员组文章数量:1405371
While learning about how macros work, I tried defining a macro that works with different datatypes without having to define it multiple types. I used _Generic
to make this task easier. However, after it didn't work, even after making changes multiple times, I asked deepseek to figure it out, which eventually came up with this:
#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"
}
In other code examples in the cpp-reference and on SO I've never seen anyone having to typecast to make this work.
Removing the typecasts (... int: printf(#var " = %d\n",(var)), \
...) shows a warning "Format specifies type 'long' but argument has type 'int'" and gives compile warning (-Wall
enabled):
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)), \
I have not been able to find out why the typecast is required here and deepseek also was not able to clear things up.
Why is the typecast necessary here and where is it documented?
While learning about how macros work, I tried defining a macro that works with different datatypes without having to define it multiple types. I used _Generic
to make this task easier. However, after it didn't work, even after making changes multiple times, I asked deepseek to figure it out, which eventually came up with this:
#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"
}
In other code examples in the cpp-reference and on SO I've never seen anyone having to typecast to make this work.
Removing the typecasts (... int: printf(#var " = %d\n",(var)), \
...) shows a warning "Format specifies type 'long' but argument has type 'int'" and gives compile warning (-Wall
enabled):
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)), \
I have not been able to find out why the typecast is required here and deepseek also was not able to clear things up.
Why is the typecast necessary here and where is it documented?
Share Improve this question edited Mar 8 at 20:51 LLL asked Mar 8 at 14:33 LLLLLL 771 silver badge6 bronze badges 9 | Show 4 more comments1 Answer
Reset to default 6the #define
simply edits the code nothing more.
when you write
#define FOO(var) _Generic((var), \
int: printf(#var " = %d\n", (var)), \
double: printf(#var " = %lf\n",(var)), \
long: printf(#var " = %ld\n",(var)), \
char: printf(#var " = '%c'\n",(var)), \
float: printf(#var " = %f\n", (var)), \
default:printf(#var " = unknown type\n"))
int main(void) {
int a = 3;
FOO(a);
}
After the preprocessing is done it becomes behind the scenes
int main(void) {
int a = 3;
_Generic((a),
int: printf("a" " = %d\n", (a)),
double: printf("a" " = %lf\n", (a)),
long: printf("a" " = %ld\n", (a)),
char: printf("a" " = '%c'\n",(a)),
float: printf("a" " = %f\n",(a)),
default:printf("a" " = unknown type\n"));
}
When a
is an int
the compiler still sees
printf("a" " = %lf\n", (a))
and the other statements as well. thus, gives you the warning complaining about the variable a
being int
while printf
expecting float
even though that statement will not be executed.
typecasting just makes the compiler consider a
as float
(in the float:
part of _Generic
and so on in the rest of it) thus not complaining about it.
by the way you probably have the -Wall
on.
Edit:
To get rid of the warning do this instead
#include <stdio.h>
#define FOO(var) printf( _Generic((var),\
int: #var " = %d\n",\
double: #var " = %lf\n",\
long: #var " = %ld\n",\
char: #var " = '%c'\n",\
float: #var " = %f\n",\
default: #var " = unknown type\n")\
, var )
int main() {
float a = 2.4f;
FOO(a);
}
本文标签: macrosGeneric in C needs typecastingStack Overflow
版权声明:本文标题:macros - _Generic in C needs typecasting? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744893752a2630938.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
_Generic
inside theprintf
, to select the format string, instead of having theprintf
inside the_Generic
. – Eric Postpischil Commented Mar 8 at 15:55_Generic
? Which compiler are you using ? What options are you using? Are you compiling for at least C11? It looks a bit as if the compiler doesn't understand_Generic
because the standard makes it clear "None of the expressions from any other generic association of the generic selection is evaluated." So, the compiler should not be complaining about the unused generic selections. But if you wrote that code in a compiler that didn't understand_Generic
, you might get such warnings. OTOH, the type names as labels might cause errors in a compiler. – Jonathan Leffler Commented Mar 8 at 17:03-Wall
: godbolt./z/aqfqYoEG8. The compiler certainly does understand_Generic
in general (or there would be fatal errors). It's just being overly aggressive by giving warnings about code which is not actually evaluated. Arguably this is a minor bug in GCC, or at least an enhancement that they should consider. – Nate Eldredge Commented Mar 8 at 20:07