在gcc语句表达式中声明数组并返回指向它的指针?
我已经考虑过了。 这是代码:在gcc语句表达式中声明数组并返回指向它的指针?,c,arrays,gcc,macros,c-preprocessor,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)); main(){ int a = 1; int b = 2; a = b; a = ({
#define IP_VAL(id) ({ \
char ip[32] = {0}; \
sprintf(ip,"192.168.0.%d",id&0xff); \
(char *)ip; \
})
它确实有效,但我想知道问题是否会由宏引起
我是这样用的:
function(IP_VAL(id));
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;
});
}
但我不确定这是否绝对可以。ip[32]
是否超出操作范围
非常感谢您编辑我的问题:)
我已经测试了如下简单示例:
function(IP_VAL(id));
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 it:
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
080483ed:
80483ed:55%推压ebp
80483ee:89 e5 mov%esp%ebp
80483f0:83 ec 20子$0x20,%esp
80483f3:c7 45 e0 01 00移动$0x1,-0x20(%ebp)
80483fa:C745E40200MOVL$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移动$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 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 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移动$0x6,-0xc(%ebp)
8048435:c7 45 f8 07 00 00 movl$0x7,-0x8(%ebp)
804843c:c7 45 fc 08 00 movl$0x8,-0x4(%ebp)
8048443:c9离开
8048444:c3 ret
所以我认为'c'和'd'就像'a'和'b',它们是'main()'堆栈中的变量。区别在于它们的范围。在这个例子中,每个“c”都有不同的地址
我认为宏“IP_VAL”可以工作,但我不知道gcc编译选项是否会影响它?这不是标准C,而是gcc扩展。它没有被安全地使用
ip
数组的生存期限制在其声明的范围内。您将返回一个指向该数组的指针,指向语句表达式的外部,该数组不再存在。有些人认为生命周期就是完整表达式的持续时间,但GCC文档中似乎没有任何内容支持这一说法。取消引用此指针可能会导致任何结果。它似乎完全靠运气起作用
将数组声明为static
将解决此问题,但是静态本地数组允许您编写一个不依赖于gcc扩展的简单函数
另一个解决问题的方法如下:
#define IP_VAL(id) \
( \
( \
{ \
struct { char ip[32]; } p; \
sprintf (p.ip, "192.168.0.%d", id&0xff); \
p; \
} \
).ip \
)
这个版本没有指向任何可能过期的局部变量的指针。< /P> C或C++?选择一个或另一个,而不是两个。这当然不好。使用函数。宏不是函数!我删除了C++标签,因为你要的是C,而你的代码没有显示任何C++。C和C++是不同的语言,也注意到是GCC扩展。这不是一个标准的C功能。这是一个不错的功能,但我无法理解两个示例之间的本质区别。一个版本有(1)一个作用域变量和(2)一个指向在作用域之外访问的变量的指针。另一个具有(1)临时结构内的临时数组,该临时结构衰减为指向其第一个元素的指针(2),该指针在该临时结构仍处于活动状态时被访问。为了更好地将其可视化,请将两个宏都重写为函数。一个返回一个指向其局部变量的指针,另一个返回一个按值的结构。为什么不简单:#define IP_VAL(id)({\char IP[32]={0};\sprintf(IP,“192.168.0.%d”,id&0xff);\IP;\})我假设它按值返回数组,类型为char[32]因此,在家长中使用是安全的expression@user377178不能按值传递数组,没有这样的东西。正因为如此,我现在可以看到这个。谢谢我的实验表明,gcc即使在通过指针时也会保留缓冲区。不过,安全总比抱歉好。