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);