程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了有没有办法让 snprintf 在丢弃的字符处恢复?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决有没有办法让 snprintf 在丢弃的字符处恢复??

开发过程中遇到有没有办法让 snprintf 在丢弃的字符处恢复?的问题如何解决?下面主要结合日常开发的经验,给出你关于有没有办法让 snprintf 在丢弃的字符处恢复?的解决方法建议,希望对你解决有没有办法让 snprintf 在丢弃的字符处恢复?有所启发或帮助;

出于本问题范围之外的原因,假设我有一组预先分配的不连续内存缓冲区。我希望能够将格式化的字符串打印到尽可能多的缓冲区中,以容纳所有字符。我不想动态分配一个足够大的缓冲区来保存生成的字符串。

有没有办法让 snprintf 在第一个丢弃的字符上“恢复”?或者有什么方法可以在不重新实现 stdlib 中的整个格式解析代码的情况下获得这种效果?

概念上:

int nwritten = snprintf(@R_262_8798@ge_buf[nextbuf++],MAX_MSG_LEN,fmt_String,var1,var2);
while (nwritten > MAX_MSG_LEN) {
   already_written += MAX_MSG_LEN;
   //It dIDn't fit in one buffer,write any remaining characters to the next buffer.
   nwritten = snprintf_REMAINDER(@R_262_8798@ge_buf[nextbuf++],already_written,var2);
}

使用该代码,这些输入

 MAX_MSG_LEN = 16;
 fmt_String = "%s: %.2f";
 char* var1 = "percent complete";
 float var2 = 45.6;
 char msgbuf[n][MAX_MSG_LEN];
 nextbuf = already_written = 0;

应该导致
@H_742_9@msgbuf[0] 包含 "percent complet"
@H_742_9@msgbuf[1] 包含 "e: 45.06"

如何实现 snprintf_REMAINDER

解决方法

char msgbuf[n][MAX_MSG_LEN];

缓冲区是连续的。我们可以(ab-)使用它,然后写入它并稍后设置零字节。

将全长 traaTing @H_742_9@msgbuf 作为一个大数组写入缓冲区。然后,如果 len 大于 16 个字节,则每 16 个字节从第 15 个字节开始向右移动 nwritten - 16 + 1 个字节。在第 15 个字节写入 '\0' 以结束字符串。并针对在 nwritten 内写入的每个块继续。

以下概念验证程序:

#include <stdio.h>
#include <stdlib.h>
#include <String.h>
#include <assert.h>
#include <stdarg.h>

#define N 10
#define MAX_MSG_LEN 16
char msgbuf[n][MAX_MSG_LEN];
size_t nextbuf;

#define MIN(a,b)  ((a)<(b)?(a):(b))

void msg_output(void) {
    for (size_t i = 0; i < nextbuf; ++i) {
        printf("msg[%zu] = (%zu) '%s`\n",i,strlen(msgbuf[i]),msgbuf[i]);
    }
}

#ifdef __GNUC__
__attribute__((__format__(__printf__,1,2)))
#endif
void msg_printf(const char *fmt,...) {
    const size_t rows = sizeof(msgbuf)/sizeof(*msgbuf);
    assert(nextbuf <= rows);
    if (nextbuf >= rows) return;

    // treat msgbuf as conTinous space
    char *buf = (char*)msgbuf + nextbuf * MAX_MSG_LEN;
    size_t bufsize = sizeof(msgbuf) - nextbuf * MAX_MSG_LEN;

    va_list va;
    va_start(va,fmt);
    int len1 = vsnprintf(buf,bufsize,fmt,va);
    va_end(va);
    assert(len1 >= 0);
    size_t len = len1;

    // insert zero bytes at specific positions
    const size_t chunk = sizeof(*msgbuf);
    while (len >= chunk) {
        const size_t want_to_move = len - chunk + 1;
        const size_t move = MIN(want_to_move,bufsize - chunk);
        memmove(&buf[chunk],&buf[chunk - 1],movE);
        buf[chunk - 1] = '\0';

        buf += chunk;
        bufsize -= chunk;
        len -= chunk;
    }
    buf += len + 1;
    buf[0] = '\0';

    // increment out buffer position
    nextbuf = (buf - (char*)msgbuf + chunk - 1) / chunk;
}

int main() {
    msg_printf("Hello world");
    msg_printf("Hello 123456789 123456789");
    msg_printf("Hello 123456789 123456789 123456789 123456789");
    msg_output();
}

输出:

@H_742_9@msg[0] = (11) 'Hello world`
msg[1] = (15) 'Hello 123456789`
msg[2] = (10) ' 123456789`
msg[3] = (15) 'Hello 123456789`
msg[4] = (15) ' 123456789 1234`
msg[5] = (14) '56789 12345678`

代码有很多错误,仅用于概念验证。最重要的是,当到达缓冲区末尾时,它会导致缓冲区溢出,@H_742_9@memmove 之前的检查不起作用。还缺少最后一个 9

我还怀疑,一个非常积极优化的编译器可以防止未定义的行为 (_FORTIFY_sourcE) 可能在 vsnprintf 调用上触发一些奇怪的行为,来自于编译器可能认为 __builTin_object_size(buf) 等于 @H_742_9@mAX_MSG_LEN,低于计算出的 bufsize。无论哪种情况,我都希望让全局变量只是一个像 char msgbuf_buf[N * MAX_MSG_LEN] 这样的连续数组,并编写一个访问器来访问像 char *msgbuf(size_t row) { return &msgbuf_buf[row * MAX_MSG_LEN]; } 这样的单个行。

至于:

有没有办法让 snprintf 在丢弃的字符处恢复?

不,没有这样的方法。

大佬总结

以上是大佬教程为你收集整理的有没有办法让 snprintf 在丢弃的字符处恢复?全部内容,希望文章能够帮你解决有没有办法让 snprintf 在丢弃的字符处恢复?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。