代码如下:
#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
位于相同的地址,但指向不同的事物。为什么?
答案 0 :(得分:2)
#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)
这是我发现的online的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)
答案 1 :(得分:1)
问题出在您的打印例程中
VueJs
您要声明一个名为<script>
export default {
data() {
return {
ticketInvoices: {},
form: new Form({
id: "",
vendor_id: "",
ticket_invoice_no: "",
ticket_invoice_date: "",
ticket_invoice_fares_total: "",
ticket_invoice_taxes_grand_total: "",
ticket_invoice_grand_total: "",
ticketInvoiceItems: [{
id: "",
ticket_invoice_id: "",
passenger_name: "",
tax_SB: 0,
tax_SRP: 0,
tax_YQ: 0,
tax_RG: 0,
tax_PK: 0,
tax_YR: 0,
tax_SF: 0,
tax_PTT: 0,
tax_OAS: 0,
tax_PSF: 0,
tax_PB: 0,
tax_OAD: 0,
fares: "",
total_tax_breakup: 0,
sub_total: ""
}]
})
};
},
computed: {
totalTax() {
let calTaxTotal =
parseInt(this.form.ticketInvoiceItems[0].tax_SB) +
parseInt(this.form.ticketInvoiceItems[0].tax_SRP) +
parseInt(this.form.ticketInvoiceItems[0].tax_YQ) +
parseInt(this.form.ticketInvoiceItems[0].tax_RG) +
parseInt(this.form.ticketInvoiceItems[0].tax_PK) +
parseInt(this.form.ticketInvoiceItems[0].tax_YR) +
parseInt(this.form.ticketInvoiceItems[0].tax_SF) +
parseInt(this.form.ticketInvoiceItems[0].tax_PTT) +
parseInt(this.form.ticketInvoiceItems[0].tax_OAS) +
parseInt(this.form.ticketInvoiceItems[0].tax_PSF) +
parseInt(this.form.ticketInvoiceItems[0].tax_PB) +
parseInt(this.form.ticketInvoiceItems[0].tax_OAD);
this.form.ticketInvoiceItems[0].total_tax_breakup = calTaxTotal;
return calTaxTotal;
}
},
}
</script>
的新变量,并打印那个变量的地址。在这种情况下,碰巧发现该变量每次进入范围都具有相同的地址。
摆脱多余的变量,以显示您感兴趣的实际变量的地址。
#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)); \
}
答案 2 :(得分:1)
两个指针tmp
和s
共享同一位置;但是,他们在不同的时间这样做。
发生上述情况的原因是此声明:
__typeof__(p) p1 = p;
它将p
的副本复制到p1
中,这是封闭代码块局部的变量。 DebugPointer
宏被扩展了两次,每次在临时作用域内创建一个名为p1
的新局部变量。
编译器会注意到两个变量p1
永远不会同时存在,因此它会重用p1
的第一个实例的空间来存储p1
的第二个实例的值
注意:现在您可能想知道为什么首先需要p1
。这样做的原因是您要向其应用&
运算符的地址。您可以改写&(p)
,但是这样的宏会很脆弱:它可以在您的示例(demo)中工作,但是调用DebugPointer(tmp+1)
会导致编译错误。