以下是代码:
#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书。我在试着理解它是如何工作的。结果看上去有点奇怪:
==== 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看起来,tmp和s两个指针驻留在同一个地址,但指向不同的东西。为什么?
发布于 2018-10-24 20:09:11
#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进行多重计算。要完成打印目标,您可以更改宏以获得前面的地址。
#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定义在线
#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参数进行多次计算,可以预先获得它的地址。
#define Sasprintf(write_to, ...) do { \
char **dest = &(write_to); \
free(*dest); \
asprintf(dest, __VA_ARGS__); \
} while(0)发布于 2018-10-24 20:08:45
这个问题在你的印刷程序中:
#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的新变量,并打印的地址,即变量。在这种情况下,它恰好计算出这个变量每次进入作用域时都有相同的地址。
去掉额外的变量,以打印您感兴趣的实际变量的地址。
#define DebugPointer(p) \
{ \
printf("%8s %20s: %p\n", #p, "address", (void*)&(p)); \
printf("%8s %20s: %p\n", #p, "points to", (void*)(p)); \
}发布于 2018-10-24 20:09:23
两个指针( tmp和s )确实共享相同的位置;但是,它们在不同的时间这样做。
作出上述声明的原因是:
__typeof__(p) p1 = p;它将p的一个副本复制到p1中,p1是一个局部性的变量,它位于封闭的代码块中。DebugPointer宏被展开两次,每次在临时作用域中创建一个名为p1的新局部变量。
编译器注意到两个变量p1从来不同时存在,因此它重用p1第一个实例的空间来存储p1第二个实例的值。
注:,现在您可能想知道为什么首先需要p1。原因是您正在将&运算符的地址应用于它。您可以编写&(p),但是这样的宏是脆弱的:它可以在您的示例(演示)中工作,但是调用DebugPointer(tmp+1)会导致编译错误。
https://stackoverflow.com/questions/52977103
复制相似问题