c - 使用宏定义两个局部变量但具有相同的地址

标签 c linux gcc macros gnu

代码如下:

#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位系统上有所不同)
  • 你的带有 memsetmemcpy 的宏并不比 strcpy 更安全;在健壮的代码中,您应该将此 strcpy 更改为 snprintf(ms.str, sizeof ms.str, "%s", str);

关于c - 使用宏定义两个局部变量但具有相同的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27221775/

相关文章:

c - Variadic 宏扩展出错了

c++ - 如何设置 ZMQ PUB/SUB 模式以仅服务于预授权订阅者

c - 使用循环展开/代码运动优化 C 代码

c - 用于在 c 中创建螺旋形状图案的嵌套循环

单次调用的 CLOCK_REALTIME 和 CLOCK_MONOTONIC

无法执行 Shellcode --> (Speicherzugriffsfehler (Speicherabzug geschrieben))

python - 在 Linux 上打包(归档)Python 项目

linux - bash if 语句

linux - gcc 命令在链接 (ld) 操作时崩溃

c - 禁用 GCC 中的所有优化选项