使用 va_arg() 解析参数时仅在 gcc-6.1.0 中发现错误

Error found only in gcc-6.1.0 while parsing the arguements using va_arg()

我发现以下在 gcc 6.1.0 中编译但在 gcc 4.4.6 中没有编译的代码出现“错误:赋值给具有数组类型的表达式”错误。

void foo(char *fmt, ...)
{
    va_list ap;
    int d;
    char *c, *s;
    typedef unsigned char mac_t[6];

    mac_t ad;   
    va_start(ap, fmt);
    while (*fmt)
    switch (*fmt++) {
    case 's':  
        s = va_arg(ap, char *);
        printf("string %s\n", s);
     break;
    case 'd':              /* int */
        d = va_arg(ap, int);
        printf("int %d\n", d);
    break;
    case 'c':              /* char */
        ad = va_arg(ap, mac_t);  //**** error here only on gcc 6.1.0 compiler 
        printf("With unsigned char: char %c.%c.%c.%c.%c.%c\n", ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);                                              
    }
    va_end(ap);
}
int main()
{
    foo("%c", "AABBCC");
}    

如何解决这个错误?在gcc 4.4.6中,编译顺利通过。由于某些原因,我只需要使用 gcc 6.1.0 编译器。

你有:

typedef unsigned char mac_t[6];
mac_t ad;   

然后你尝试:

ad = va_arg(ap, mac_t);

当,你传递了这样的参数:

foo("%c", "AABBCC");

这是一个错误。您不能分配给数组。此外,"AABBCC" 是一个 char 数组 [7],因为 NUL 终止字符串文字。不过,那没关系。 foo() 收到一个 char *,因为数组类型衰减到包含其第一个元素地址的指针。

如果将 -std=c99 传递给 GCC,您应该能够看到错误。显然,这可以进行更严格的检查。

gcc -std=c99 -W -Wall -O c.c
c.c: In function ‘foo’:
c.c:25:12: error: incompatible types when assigning to type ‘mac_t’ from type ‘unsigned char *’
         ad = va_arg(ap, mac_t);  // error here only on gcc 6.1.0 compiler
            ^

要解决此问题,请告诉 va_arg 您正在解析指针。如果必须复制内容,则使用strncpy.

strncpy((void *)ad, va_arg(ap, char *), sizeof(ad));

我们强制 ad,因为 strncpy 期望 char * 作为第一个参数。