首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >两个指针位于同一地址,但指向不同的事物。

两个指针位于同一地址,但指向不同的事物。
EN

Stack Overflow用户
提问于 2018-10-24 20:01:18
回答 3查看 119关注 0票数 2

以下是代码:

代码语言:javascript
复制
#define _GNU_SOURCE
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DebugPointer(p)                                         \
    {                                                           \
        __typeof__(p) p1 = p;                                   \
        printf("%8s %20s: %p\n", #p, "address", (void*)&(p1));  \
        printf("%8s %20s: %p\n", #p, "points to", (void*)(p1)); \
    }


// memory-safe asprintf, implemented as a macro
#define Sasprintf(write_to, ...)            \
    {                                       \
        char* tmp = (write_to);             \
        printf("==== before asprintf\n");   \
        DebugPointer(tmp);                  \
        DebugPointer(write_to);             \
        asprintf(&(write_to), __VA_ARGS__); \
        printf("==== after  asprintf\n");   \
        DebugPointer(tmp);                  \
        DebugPointer(write_to);             \
        free(tmp);                          \
    }

int main() {
    char* s = NULL;
    int n = 0;
    Sasprintf(s, "%s", "aa\n");
    Sasprintf(s, "%s%s", s, "bb\n");
    Sasprintf(s, "%s%s", s, "cc\n");
    printf("string: %s\n", s);
    free(s);
}

Sasprintf宏摘自21世纪c书。我在试着理解它是如何工作的。结果看上去有点奇怪:

代码语言:javascript
复制
==== before asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: (nil)
       s              address: 0x7ffe8b767cd8
       s            points to: (nil)
==== after  asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: (nil)
       s              address: 0x7ffe8b767cd8
       s            points to: 0x560969cae6e0
==== before asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: 0x560969cae6e0
       s              address: 0x7ffe8b767cd8
       s            points to: 0x560969cae6e0
==== after  asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: 0x560969cae6e0
       s              address: 0x7ffe8b767cd8
       s            points to: 0x560969cae700
==== before asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: 0x560969cae700
       s              address: 0x7ffe8b767cd8
       s            points to: 0x560969cae700
==== after  asprintf
     tmp              address: 0x7ffe8b767cd8
     tmp            points to: 0x560969cae700
       s              address: 0x7ffe8b767cd8
       s            points to: 0x560969cae6e0
string: aa
bb
cc

看起来,tmps两个指针驻留在同一个地址,但指向不同的东西。为什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-10-24 20:09:11

代码语言:javascript
复制
#define DebugPointer(p)                                         \
    {                                                           \
        __typeof__(p) p1 = p;                                   \
        printf("%8s %20s: %p\n", #p, "address", (void*)&(p1));  \
        printf("%8s %20s: %p\n", #p, "points to", (void*)(p1)); \
    }

因此,您要打印p1的地址,它是DebugPointer每次调用的本地地址,因此每次调用它时都允许相同的地址。

p1的目的似乎是避免对宏参数p进行多重计算。要完成打印目标,您可以更改宏以获得前面的地址。

代码语言:javascript
复制
#define DebugPointer(p)                                         \
    do {                                                        \
        __typeof__(&(p)) p1 = &(p);                             \
        void *p2 = *p1;                                         \
        printf("%8s %20s: %p\n", #p, "address", (void*)p1);     \
        printf("%8s %20s: %p\n", #p, "points to", p2);          \
    } while(0)

下面是我找到的Sasprintf定义在线

代码语言:javascript
复制
#define Sasprintf(write_to,  ...) {           \
    char *tmp_string_for_extend = (write_to); \
    asprintf(&(write_to), __VA_ARGS__);       \
    free(tmp_string_for_extend);              \
}

它使用临时命令来存储原指针,该指针应该是由以前对Sasprintf的调用(或初始化为NULL)分配的。asprintf调用可能会改变它所指向的位置。现在,宏可以对原始指针调用free

为了避免对write_to参数进行多次计算,可以预先获得它的地址。

代码语言:javascript
复制
#define Sasprintf(write_to,  ...) do { \
    char **dest = &(write_to);         \
    free(*dest);                       \
    asprintf(dest, __VA_ARGS__);       \
} while(0)
票数 2
EN

Stack Overflow用户

发布于 2018-10-24 20:08:45

这个问题在你的印刷程序中:

代码语言:javascript
复制
#define DebugPointer(p)                                         \
    {                                                           \
        __typeof__(p) p1 = p;                                   \
        printf("%8s %20s: %p\n", #p, "address", (void*)&(p1));  \
        printf("%8s %20s: %p\n", #p, "points to", (void*)(p1)); \
    }

您正在声明一个名为p1的新变量,并打印的地址,即变量。在这种情况下,它恰好计算出这个变量每次进入作用域时都有相同的地址。

去掉额外的变量,以打印您感兴趣的实际变量的地址。

代码语言:javascript
复制
#define DebugPointer(p)                                        \
    {                                                          \
        printf("%8s %20s: %p\n", #p, "address", (void*)&(p));  \
        printf("%8s %20s: %p\n", #p, "points to", (void*)(p)); \
    }
票数 1
EN

Stack Overflow用户

发布于 2018-10-24 20:09:23

两个指针( tmps )确实共享相同的位置;但是,它们在不同的时间这样做。

作出上述声明的原因是:

代码语言:javascript
复制
__typeof__(p) p1 = p;

它将p的一个副本复制到p1中,p1是一个局部性的变量,它位于封闭的代码块中。DebugPointer宏被展开两次,每次在临时作用域中创建一个名为p1的新局部变量。

编译器注意到两个变量p1从来不同时存在,因此它重用p1第一个实例的空间来存储p1第二个实例的值。

注:,现在您可能想知道为什么首先需要p1。原因是您正在将&运算符的地址应用于它。您可以编写&(p),但是这样的宏是脆弱的:它可以在您的示例(演示)中工作,但是调用DebugPointer(tmp+1)会导致编译错误。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52977103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档