相关疑难解决方法(0)

泛型表达式中的副作用

我正在使用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和 …

c generics c11

25
推荐指数
1
解决办法
611
查看次数

_Generic填补一些联盟

我想使用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)

c c11

8
推荐指数
1
解决办法
153
查看次数

C宏_Generic产生意外的编译器错误

使用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)

c c-preprocessor c11

7
推荐指数
1
解决办法
163
查看次数

GCC:为什么无法在 -std=c11 -Wall 下编译干净的 printf("%f\n", f16) ?

示例代码:

#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?是否应该有所了解? …

c printf gcc language-lawyer half-precision-float

4
推荐指数
1
解决办法
471
查看次数

带有 _Generic 的奇怪 gcc 警告

我有一些代码根据参数的类型使用 _Generic 来调度函数。我不明白 gcc 生成的警告。

\n

编译用gcc main.c

\n
#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 的参数匹配到错误的行:

\n
main.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)

c macros

3
推荐指数
1
解决办法
390
查看次数