我正在使用new _Generic
关键字进行一些实验,偶然发现了一个关于多个评估的特殊情况.请参阅以下内容:
#include <stdio.h>
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)
int main(void)
{
const char *s = "foo";
write_char(*s++);
write_char(*s++);
write_char(*s++);
putchar('\n');
}
Run Code Online (Sandbox Code Playgroud)
这个编译很好并且用GCC产生预期的结果:
$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus
foo
Run Code Online (Sandbox Code Playgroud)
另一方面,Clang输出了一个很大的鸣笛警告:
$ clang -std=c11 plusplus.c -o plusplus
plusplus.c:9:18: warning: multiple unsequenced modifications to 's'
[-Wunsequenced]
write_char(*s++);
^~
plusplus.c:3:32: note: expanded from macro 'write_char'
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)
...
Run Code Online (Sandbox Code Playgroud)
结果如预期:
$ ./plusplus
foo
Run Code Online (Sandbox Code Playgroud)
我检查了标准草案,该草案说明(PDF格式第97页):
不评估通用选择的控制表达式.
这似乎准确地解决了宏中的副作用问题(例如,MIN
和 …
我想使用C11 _Generic
关键字根据静态类型填充联合,如:
typedef union {
double d;
long l;
const char*s;
void*p;
} ty;
#define make_ty(X) _Generic((X), \
double: (ty){.d=(X)}, \
long: (ty){.l=(X)}, \
const char*: (ty){.s=(X)}, \
default: (ty){.p=(X)})
ty from_double(double x) { return make_ty(x); }
ty from_string(const char*s) { return make_ty(s); }
ty from_long(long l) { return make_ty(l);}
Run Code Online (Sandbox Code Playgroud)
但是这不能编译,例如GCC 5.3给出(with gcc -std=c11 -Wall
):
u.c: In function ‘from_double’:
u.c:11:35: error: incompatible types when initializing type ‘const char *’
using type ‘double’
const char*: (ty){.s=(X)}, \ …
Run Code Online (Sandbox Code Playgroud) 使用gcc.exe(Rev3,由MSYS2项目构建)8.2.0。
我试图建立一个宏来自动进行两种类型之间的类型转换,其中两个参数绝不能是同一类型。我的问题是,如果我也不包含相同类型的大小写,则编译器将引发错误。我想要的是:
#include <stdio.h>
#include <stdint.h>
// Macro to return string based on two different types
#define bob( to, from ) \
_Generic( to , \
int32_t: _Generic(from, \
int16_t: "s-l", \
int8_t: "c-l" ) , \
int16_t: _Generic(from, \
int32_t: "l-s", \
int8_t: "c-s") , \
int8_t:_Generic(from, \
int32_t: "l-c", \
int16_t: "s-c") \
)
void main(void)
{
int32_t i1;
int16_t s1;
int8_t c1;
printf("%s\n", bob(i1,s1));
printf("%s\n", bob(i1,c1));
printf("%s\n", bob(s1,c1));
printf("%s\n", bob(s1,i1));
printf("%s\n", bob(c1,s1));
printf("%s\n", bob(c1,s1));
}
Run Code Online (Sandbox Code Playgroud)
$ gcc …
Run Code Online (Sandbox Code Playgroud) 示例代码:
#include <stdio.h>
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
#ifdef FLT16_MAX
_Float16 f16;
int main(void)
{
printf("%f\n", f16);
return 0;
}
#endif
Run Code Online (Sandbox Code Playgroud)
调用:
# gcc trunk on linux on x86_64
$ gcc t0.c -std=c11 -Wall
Run Code Online (Sandbox Code Playgroud)
预期诊断:
<nothing>
Run Code Online (Sandbox Code Playgroud)
实际诊断:
t0.c:9:14: warning: format '%f' expects argument of type 'double', but argument 2 has type '_Float16' [-Wformat=]
9 | printf("%f\n", f16);
| ~^ ~~~
| | |
| | _Float16
| double
Run Code Online (Sandbox Code Playgroud)
这是否意味着在__STDC_WANT_IEC_60559_TYPES_EXT__
AND 下如果FLT16_MAX
定义了 gcc 不知道printf
可以与 一起使用_Float16
?是否应该有所了解? …
我有一些代码根据参数的类型使用 _Generic 来调度函数。我不明白 gcc 生成的警告。
\n编译用gcc main.c
#include <stdio.h>\n\n#define FOOBAR(x) _Generic((x), \\\n int *: foo(x), \\\n long *: bar(x) \\\n)\n\nvoid foo(int* x) {\n printf("foo\\n");\n}\n\nvoid bar(long* y) {\n printf("bar\\n");\n}\n\nint main() {\n int a = 1111;\n long b = 2222;\n\n FOOBAR(&a);\n FOOBAR(&b);\n}\n
Run Code Online (Sandbox Code Playgroud)\n现在,这段代码确实可以编译,并且 _Generic 按预期工作,即“foo”出现,然后“bar”出现。然而,编译器(gcc 和 clang)生成一个奇怪的警告,看起来它会将 _Generic 的参数匹配到错误的行:
\nmain.c: In function \xe2\x80\x98main\xe2\x80\x99:\nmain.c:20:12: warning: passing argument 1 of \xe2\x80\x98bar\xe2\x80\x99 from incompatible pointer type [-Wincompatible-pointer-types]\n 20 | FOOBAR(&a);\n | ^~\n | |\n | int *\nmain.c:5:15: note: in definition …
Run Code Online (Sandbox Code Playgroud)