C11 _Generic() - 如何抑制与选择器不匹配的选择的 gcc 代码评估(错误检查)

C11 _Generic() - How can I suppress gcc code evaluation (Error check) for selections which are not matching with selector

P.S.- 为了简单起见,我使用了 int 和 int *,它也可以是 struct 和 struct *.

我正在尝试实现一个宏,以将一个变量中存在的数据复制到另一个独立于变量数据类型的变量,在下面的解决方案中,我使用了“_Generic”编译器功能。 程序 1:

#include<stdio.h>
#include <string.h>

#define copyVar(var,newVar) _Generic((var),int:({memcpy(newVar,(void *)&var,sizeof(int));}),\
        int *:({memcpy(newVar,(void *)var,sizeof(int));}),default:newVar=var)
int main() {
   int data = 2;
   int *copy;copy = (int *)malloc(sizeof(int));
   copyVar(data,copy);
   printf("copied Data=%i",*copy);
}

计划 2:

  #include<stdio.h>
  #include <string.h>

    #define copyVar(var,newVar) _Generic((var),int:({memcpy(newVar,(void *)&var,sizeof(int));}),\
                int *:({memcpy(newVar,(void *)var,sizeof(int));}),default:newVar=var)
 int main() {
           int data = 2;
           int *copy;copy = (int *)malloc(sizeof(int));
           copyVar(&data,copy);
           printf("copied Data=%i",*copy);
}

现在的问题是,尽管有一些警告,'program 1' 还是成功编译了。 但是在编译程序 2 gcc 时抛出错误:

error: lvalue required as unary '&' operand #define copyVar(var,newVar) _Generic((var),int:({memcpy(newVar,(void *)&var,sizeof(int));}),

而且我认为这是由于 _Generic int: 选择得到了一个多符号的预处理

(void *)&&var

为什么 gcc 评估所有选择?

您的代码有各种问题:您将数据复制到一个未初始化的指针中,您有多余的 void* 转换,您将 _Generic 视为某种复合语句而不是表达式,等等。

但是为了回答您的问题,您的代码不起作用,因为 &something 的结果不是左值。因为 & 操作符需要一个左值,所以你不能做 & &something。 (而且您也不能执行 &&something,因为它被 "maximum munch rule" 视为 && 运算符。)

因此您的代码无法正常工作的原因与此代码无法正常工作的原因相同:

int x;
int**p = & &x;

gcc 告诉你 &x 不是左值:

lvalue required as unary '&' operand


编辑 - 澄清

_Generic 宏与任何宏一样,其工作方式类似于预处理器文本替换。所以当你在宏中有这段代码时:

_Generic((var), ...
int: ... (void *)&var
int*: ... (void)var

它被预处理为

_Generic((&data), ...
int: ... (void *)& &data
int*: ... (void)&data

并对_Generic表达式的所有路径进行预处理。 _Generic 本身不是预处理器的一部分,但稍后会被评估,就像任何包含运算符的表达式一样。检查整个表达式的句法正确性,即使只计算和执行表达式的一部分。

_Generic 的缩进原始用法是这里的函数指针

#define copyVar(var,newVar) \
     _Generic((var),        \
        int:    function1,  \
        int*:   function2,  \
        default:function3)(&(var), &(newVar))

此处通用表达式选择函数,然后将此函数应用于任何参数。

您将不得不编写对应于三种不同情况的三个存根函数。

如果您的头文件中有它们小而漂亮的 inline,优化器通常会确保此机制没有 运行 时间开销。

这可以用二级_Generic来解决

#define copyVar(var,newVar) \
    _Generic((var), \
    int  :   ({  __auto_type _v = var; memcpy(newVar, (void *) _Generic((_v), int: &_v , int *: _v)  , sizeof(int));}) , \
    int *:   ({  __auto_type _v = var; memcpy(newVar, (void *) _v                                    , sizeof(int));}) , \
    default: newVar=var \
)