实现你自己的 printf
我正在尝试实现C printf,但使用%s
,我使用{s}
。而不是%d
... {d}
。而不是%C
... {C}
(有点像Python/C#/Java的位置字符串格式ARGS ARGS,而不是数字位置,而是数据类型的规格)。它还应该逃脱其他卷曲括号,以便{{}
变成{
。这一切都起作用,除非我传递{{
作为测试的一部分。 Valgrind告诉我,这可能是由于您的程序错误地编写了堆块的末尾并损坏了堆元数据
。这是代码:
#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 != '\0') {
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'
'{'
实际输出:
- GCC 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'
- clang 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'
'{}}'
如您所见,除最后一个测试外,所有测试都可以正常工作。我会做错什么?您还可以建议改善我的代码并减少内存泄漏的方法吗?
I am trying to implement the C printf but with instead of %s
, I use {s}
. Instead of %d
... {d}
. Instead of %c
... {c}
(Somewhat like Python/C#/Java's positional string format args but instead of numeric positions there are specifications of the data type). It should also escape additional curly brackets such that {{}
becomes {
. It all works except when I pass in {{
as part of a test. Valgrind informs me that This is probably caused by your program erroneously writing past the end of a heap block and corrupting heap metadata
. This is the code:
#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 != '\0') {
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);
}
These are the tests:
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("{{"));
Expected Output:
'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'
'{'
Actual Output:
- gcc 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'
- clang 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'
'{}}'
As you can see, all but the last tests work properly. What could I be doing wrong? Also can you suggest ways to improve my code and cut down on memory leaks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
经过大量的重构,最终有效的是检查下一个字符是否不是
nul
,然后递增指针。After a lot of refactoring, what ultimately worked was checking whether the next character is not
NUL
, then incrementing the pointer.