实现你自己的 printf
Implementing your own printf
我正在尝试实现 C printf,但我使用 {s}
而不是 %s
。而不是 %d
... {d}
。而不是 %c
... {c}
(有点像 Python/C#/Java 的位置字符串格式参数,但不是数字位置,而是数据类型的规范)。它还应该转义额外的大括号,使 {{}
变为 {
。这一切都有效,除非我在 {{
作为测试的一部分通过。 Valgrind 告诉我 This is probably caused by your program erroneously writing past the end of a heap block and corrupting heap metadata
。这是代码:
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mr_asprintf(const char *format, ...) {
if (strlen(format) == 0) { return calloc(1, sizeof(char)); }
char buf[strlen(format) * 2];
memset(buf, 0, sizeof(buf));
va_list args;
va_start(args, format);
while (*format != '[=10=]') {
if (*format == '{') {
format++;
if (*format == '{') {
sprintf(buf + strlen(buf), "%c", '{');
} else if (*format == 's') {
sprintf(buf + strlen(buf), "%s", va_arg(args, const char*));
} else if (*format == 'i') {
sprintf(buf + strlen(buf), "%d", va_arg(args, int));
}
if (*format++ == '}') {}
} else if (*format == '}') {
sprintf(buf + strlen(buf), "%c", '}');
} else {
sprintf(buf + strlen(buf), "%c", *format);
}
format++;
}
va_end(args);
return strdup(buf);
}
这些是测试:
printf("'%s'\n", mr_asprintf("Gaius Julius Caesar Augustus Germanicus"));
printf("'%s'\n", mr_asprintf("Nickname: {s}", "Caligula"));
printf("'%s'\n", mr_asprintf("Reign: {i} AD - {i} AD", 37, 41));
printf("'%s'\n",
mr_asprintf("born: {s} {i}, {i} in {s}", "August", 31, 12, "Antium"));
printf("'%s'\n", mr_asprintf("Roman emperor #{i}", 3));
printf("'%s'\n", mr_asprintf("Roman emperor #{i}}", 3));
printf("'%s'\n", mr_asprintf(""));
printf("'%s'\n", mr_asprintf("}bae}ccac {i}bdbb{i}bb{i}}dd b", 394603702, 511917921,
721200806));
printf("'%s'\n", mr_asprintf("{{"));
预期输出:
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{'
实际输出:
- 海湾合作委员会 10.3.0
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{Gaius Julius Caesar Augustus Germanicus'
- 叮当声 8
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{}}'
如您所见,除最后一个测试外,所有测试均正常运行。我做错了什么?您还可以建议改进我的代码并减少内存泄漏的方法吗?
经过大量重构,最终起作用的是检查下一个字符是否不是 NUL
,然后递增指针。
我正在尝试实现 C printf,但我使用 {s}
而不是 %s
。而不是 %d
... {d}
。而不是 %c
... {c}
(有点像 Python/C#/Java 的位置字符串格式参数,但不是数字位置,而是数据类型的规范)。它还应该转义额外的大括号,使 {{}
变为 {
。这一切都有效,除非我在 {{
作为测试的一部分通过。 Valgrind 告诉我 This is probably caused by your program erroneously writing past the end of a heap block and corrupting heap metadata
。这是代码:
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mr_asprintf(const char *format, ...) {
if (strlen(format) == 0) { return calloc(1, sizeof(char)); }
char buf[strlen(format) * 2];
memset(buf, 0, sizeof(buf));
va_list args;
va_start(args, format);
while (*format != '[=10=]') {
if (*format == '{') {
format++;
if (*format == '{') {
sprintf(buf + strlen(buf), "%c", '{');
} else if (*format == 's') {
sprintf(buf + strlen(buf), "%s", va_arg(args, const char*));
} else if (*format == 'i') {
sprintf(buf + strlen(buf), "%d", va_arg(args, int));
}
if (*format++ == '}') {}
} else if (*format == '}') {
sprintf(buf + strlen(buf), "%c", '}');
} else {
sprintf(buf + strlen(buf), "%c", *format);
}
format++;
}
va_end(args);
return strdup(buf);
}
这些是测试:
printf("'%s'\n", mr_asprintf("Gaius Julius Caesar Augustus Germanicus"));
printf("'%s'\n", mr_asprintf("Nickname: {s}", "Caligula"));
printf("'%s'\n", mr_asprintf("Reign: {i} AD - {i} AD", 37, 41));
printf("'%s'\n",
mr_asprintf("born: {s} {i}, {i} in {s}", "August", 31, 12, "Antium"));
printf("'%s'\n", mr_asprintf("Roman emperor #{i}", 3));
printf("'%s'\n", mr_asprintf("Roman emperor #{i}}", 3));
printf("'%s'\n", mr_asprintf(""));
printf("'%s'\n", mr_asprintf("}bae}ccac {i}bdbb{i}bb{i}}dd b", 394603702, 511917921,
721200806));
printf("'%s'\n", mr_asprintf("{{"));
预期输出:
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{'
实际输出:
- 海湾合作委员会 10.3.0
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{Gaius Julius Caesar Augustus Germanicus'
- 叮当声 8
'Gaius Julius Caesar Augustus Germanicus'
'Nickname: Caligula'
'Reign: 37 AD - 41 AD'
'born: August 31, 12 in Antium'
'Roman emperor #3'
'Roman emperor #3}'
''
'}bae}ccac 394603702bdbb511917921bb721200806}dd b'
'{}}'
如您所见,除最后一个测试外,所有测试均正常运行。我做错了什么?您还可以建议改进我的代码并减少内存泄漏的方法吗?
经过大量重构,最终起作用的是检查下一个字符是否不是 NUL
,然后递增指针。