实现你自己的 printf

发布于 2025-01-18 04:27:01 字数 3002 浏览 2 评论 0原文

我正在尝试实现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'
'{'

实际输出:

  1. 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'
  1. 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:

  1. 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'
  1. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

皇甫轩 2025-01-25 04:27:01

经过大量的重构,最终有效的是检查下一个字符是否不是nul,然后递增指针。

After a lot of refactoring, what ultimately worked was checking whether the next character is not NUL, then incrementing the pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文