C snprintf中的strlen调用是否导致此故障?

C snprintf中的strlen调用是否导致此故障?,c,segmentation-fault,strlen,printf,C,Segmentation Fault,Strlen,Printf,我有一个void*,称之为data,我知道它的长度,但不是以null结尾的。我这样调用snprintf(line,sizeof(line),“%*s”,n,(const char*)数据)其中n是已知长度。这几乎总是可行的,但偶尔会导致断层 无论何时发生SEGFULT,回溯都表明问题出在strlen内部。当我在gdb中打印数据时,我看到类似这样的东西 (gdb) p n $1 = 88 (gdb) p (const char*) data $2 = 0x1d752fa8 "JASDF" ...

我有一个
void*
,称之为
data
,我知道它的长度,但不是以null结尾的。我这样调用
snprintf(line,sizeof(line),“%*s”,n,(const char*)数据)
其中
n
是已知长度。这几乎总是可行的,但偶尔会导致断层

无论何时发生SEGFULT,回溯都表明问题出在strlen内部。当我在gdb中打印
数据时,我看到类似这样的东西

(gdb) p n
$1 = 88
(gdb) p (const char*) data
$2 = 0x1d752fa8
"JASDF" ... "ADS"<Address 0x1d753000 out of bounds>
(gdb) p 0x1d753000-0x1d752fa8
$3 = 88

EDIT要回答我自己关于解决方法的问题,strncpy是一个更适合调用的函数。我习惯使用snprintf。

看起来你是对的。无法保证
printf
不会调用
strlen
,即使它在给定的上下文中不一定要调用。你在撒谎,你提供了一些不是C字符串的东西作为
%s
格式说明符的参数,因此你打破了
printf
的约定。未定义的行为结果。

我认为您的分析是正确的。如果缓冲区不是以null结尾的,则strlen调用将一直读取,直到找到
\0
。如果它运行超过段的末尾(而下一段无效),则会产生异常

解决方案是将其空终止,或者将其放入另一个可以空终止的缓冲区。

解决方法是使用
memcpy()

size\u t validlen=n
snprintf(行,大小(行),“%*s”,n,(常量字符*)数据)

数据
不是以零结尾吗?那你做错了

snprintf(line, sizeof(line), "%.*s", n, (const char*)data);
注意点

对于字符串,如果所需的输出(屏幕上)长度-输入长度是第二个
*
,则
*
中的第一个
*
<代码>手动打印F
了解更多信息


显然,在
%*s
格式化的情况下可能会调用strlen(),因为它需要知道是否需要填充输出以及如何填充输出。

“%.*s”是一种方法-不需要冗余复制。我的回答中没有冗余复制-只有一个副本,使用
memcpy()
而不是
snprintf()
。请参阅下面我的回答。格式化已经支持非0终止的字符串。
%s
支持非0终止的字符串:
%.*s
真正的问题是他的格式字符串错误,请使用
“%.*s”
而不是
“%*s”
您是对的。手册页在讨论非空终止字符串和精度修饰符时非常明确。
size_t validlen = n < sizeof line ? n : (sizeof line - 1);
memcpy(line, data, validlen);
line[validlen] = '\0';
snprintf(line, sizeof(line), "%.*s", n, (const char*)data);