大佬教程收集整理的这篇文章主要介绍了有没有办法让 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,请注明来意。