在gcc语句表达式中声明一个数组并返回一个指向它的指针?

时间:2016-11-08 12:26:20

标签: c arrays gcc macros c-preprocessor

我已经考虑过了。 这就是代码:

#define IP_VAL(id) ({ \
    char ip[32] = {0}; \
    sprintf(ip,"192.168.0.%d",id&0xff); \
    (char *)ip; \
})

它确实有效,但我想知道宏是否会引起问题?

我这样用过:

function(IP_VAL(id));

但我不确定它是否绝对正常。 ip[32]是否超出了行动范围?

非常感谢您编辑我的问题:)

我测试了这样一个简单的例子:

main(){
    int a = 1;
    int b = 2;
    a = b;
    a = ({
            int c = 3;
            c;
        });
    a = ({
            int d = 4;
            d;
        });
    a = ({
            int c = 5;
            c;
        });
    ({
        int c = 6;
        c;
    });
    ({
        int c = 7;
        c;
    });
    ({
        int c = 8;
        c;
    });
}

然后objdump:

080483ed <main>:
 80483ed:   55                      push   %ebp
 80483ee:   89 e5                   mov    %esp,%ebp
 80483f0:   83 ec 20                sub    $0x20,%esp
 80483f3:   c7 45 e0 01 00 00 00    movl   $0x1,-0x20(%ebp)
 80483fa:   c7 45 e4 02 00 00 00    movl   $0x2,-0x1c(%ebp)
 8048401:   8b 45 e4                mov    -0x1c(%ebp),%eax
 8048404:   89 45 e0                mov    %eax,-0x20(%ebp)
 8048407:   c7 45 e8 03 00 00 00    movl   $0x3,-0x18(%ebp)
 804840e:   8b 45 e8                mov    -0x18(%ebp),%eax
 8048411:   89 45 e0                mov    %eax,-0x20(%ebp)
 8048414:   c7 45 ec 04 00 00 00    movl   $0x4,-0x14(%ebp)
 804841b:   8b 45 ec                mov    -0x14(%ebp),%eax
 804841e:   89 45 e0                mov    %eax,-0x20(%ebp)
 8048421:   c7 45 f0 05 00 00 00    movl   $0x5,-0x10(%ebp)
 8048428:   8b 45 f0                mov    -0x10(%ebp),%eax
 804842b:   89 45 e0                mov    %eax,-0x20(%ebp)
 804842e:   c7 45 f4 06 00 00 00    movl   $0x6,-0xc(%ebp)
 8048435:   c7 45 f8 07 00 00 00    movl   $0x7,-0x8(%ebp)
 804843c:   c7 45 fc 08 00 00 00    movl   $0x8,-0x4(%ebp)
 8048443:   c9                      leave  
 8048444:   c3                      ret

所以我认为&#39; c&#39;并且&#39; d&#39;就像&#39; a&#39;和&#39; b&#39;,它们是&#39; main()&#39;堆栈中的变量。不同之处在于它们的范围。在示例中,每个&#39; c&#39;有不同的地址。

我认为宏观&#39; IP_VAL&#39;有效,但我不知道gcc编译选项是否会影响它?

1 个答案:

答案 0 :(得分:2)

这不是标准C而是gcc扩展。它没有得到安全使用。

ip数组的生命周期仅限于声明它的范围。您将指向此数组的指针返回到statement-expression的外部,其中数组不再存在。有些人认为,生命周期是完整表达的持续时间,但GCC文档中没有任何内容似乎支持这种说法。取消引用此指针可能会产生任何结果。它似乎完全符合运气。

将数组声明为static将解决问题,但是静态本地数组允许您编写一个不依赖于gcc扩展的简单函数。

解决问题的另一种方法如下:

#define IP_VAL(id) \
    ( \
     ( \
      { \
       struct { char ip[32]; } p; \
       sprintf (p.ip, "192.168.0.%d", id&0xff); \
       p; \
      } \
     ).ip \
    )

此版本没有指向任何潜在过期局部变量的指针。