_printf_p函数异常行为探究:为何触发断言失败?
_printf_p未连续使用起始位置参数触发断言失败的原因分析
先看给出的_printf_p调用示例:
_printf_p("%1$c\n", 'a', 'b', 'c'); // OK _printf_p("%2$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%3$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%1$c %2$c\n", 'a', 'b', 'c'); // OK _printf_p("%2$c %1$c\n", 'a', 'b', 'c'); // OK _printf_p("%1$c %3$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%3$c %1$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%2$c %3$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%3$c %2$c\n", 'a', 'b', 'c'); // Debug Assertion Failed _printf_p("%1$c %2$c %3$c\n", 'a', 'b', 'c'); // OK _printf_p("%3$c %2$c %1$c\n", 'a', 'b', 'c'); // OK _printf_p("%2$c %1$c %3$c\n", 'a', 'b', 'c'); // OK
这个现象的核心原因是微软CRT对_printf_p的参数使用有严格的连续性检查:
- 当使用位置格式化参数(
%n$形式)时,CRT的断言逻辑会验证:所有编号小于等于你用到的最大位置编号的参数,必须全部被格式字符串引用到。 - 要么你用完所有传入的可变参数(比如传了3个,格式里引用了1、2、3号,不管顺序),要么你引用的参数是从1号开始的连续序列(比如传了3个,只引用1号,或者1+2号)。
举个具体例子:
- 如果你用了
%2$c,最大位置编号是2,但没引用1号参数,断言就会触发; - 如果你用了
%1$c %3$c,最大位置编号是3,但没引用2号参数,同样触发断言; - 哪怕你打乱顺序用
%3$c %2$c %1$c,因为1、2、3号都被引用了,不管顺序,断言不会触发; - 只引用1号或者1+2号,因为最大位置编号对应的所有前置参数都被用到了,也没问题。
这个约束是微软为了提升格式化函数的安全性设计的——避免开发者因疏忽跳过参数,或者位置编号写错导致的逻辑错误,通过断言提前暴露这类问题。
内容的提问来源于stack exchange,提问作者stanchcorder6
相关产品推荐
相关产品推荐

