代码如下:
#include"stdio.h"
#define MySTRING(ident, str) \
({\
char str_##ident[16]; \
memset((char *)str_##ident, 0x00, sizeof(str_##ident)); \
memcpy(str_##ident, (str), strlen((str))); \
str_##ident; \
})
int main(int argc, char **argv)
{
printf("%u, %u\n", MySTRING(qw, "1.1.1.1"), MySTRING(er, "2.2.2.2"));
}
测试结果:
[root@cza temp]# gcc -O0 ./fly.c
[root@cza temp]# ./a.out
3959297344, 3959297360
[root@cza temp]# gcc -O2 ./fly.c
[root@cza temp]# ./a.out
2017090240, 2017090240
似乎 gcc optimistic 对此有所作为。
第二个结果不是我想要的,但在我的应用程序构建模板中,O2 已经设置。
我想知道为什么 O2 使它与众不同的细节,或者它是 GCC 上的错误?
附言我的同事告诉我前缀“volatile”可以工作。
最佳答案
您的代码是一个名为 Statement Expression 的 gcc 扩展.大括号中的语句被执行,最终语句的值就是表达式的值。语句结束时,创建的任何对象都将被销毁。
在宏中没有区别;你的代码(更新:原始代码)是:
printf("%u, %u\n", ({ char ip_qw[16]; ip_qw; }), ({ char ip_er[16]; ip_er; }) );
当 ip_qw
block 结束时,ip_qw
被销毁,以便释放内存供 ip_er
使用。这解释了为什么可以看到两者的相同地址。
您的代码无效,因为 printf
函数将在 16 字节数组被销毁后访问它们的内容。
幸运的是,标准 C 有一个解决方案。按值返回的对象保证会一直存在,直到执行函数调用的语句结束。数组不能按值返回,但结构可以,所以我们可以:
#include <stdio.h>
#include <string.h>
struct MS
{
char str[16];
};
struct MS make_MS(char const *str)
{
struct MS ms;
strcpy(ms.str, str);
return ms;
}
#define MySTRING(s) make_MS(s).str
int main(int argc, char **argv)
{
printf("%s, %s\n", MySTRING("1.1.1.1"), MySTRING("2.2.2.2"));
}
注意事项:
- 对标准包含使用尖括号
- 使用
%p
打印指针(在64位系统上有所不同) - 你的带有
memset
和memcpy
的宏并不比strcpy
更安全;在健壮的代码中,您应该将此strcpy
更改为snprintf(ms.str, sizeof ms.str, "%s", str);
。
关于c - 使用宏定义两个局部变量但具有相同的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27221775/