categories: 解决方案
tags:
- C
- cpp
date: 2024-03-20 16:09:03
关于 printf 格式化输出与预期不符的分析
缺陷问题详细描述
printf 和 cout 的值不一致。
重现方法
/*******************************************************************************
* @copyright Copyright (c) 2024
*
* @author Wu Wei
* @version 0.1
* @date 2024-03-19, created.
*
* @file test_print_cast.cpp
* @brief 测试printf 打印强转的问题
* @ref C/C++中%d、%ld、%lld的含义和区别是什么? - BetaCat的回答 - 知乎
* https://www.zhihu.com/question/283460749/answer/432742267
******************************************************************************/
/**
* 输出:
* (%ld)d: 140722676870488
* (%ld)(long)d: 3
*/
#include <iostream>
int main(int argc, char const *argv[])
{
double d = 10 * 1.0 / 3;
printf("(%%ld)d: %ld\n", d);
printf("(%%ld)(long)d: %ld\n", (long)d);
return 0;
}
原因分析
printf
是通过 “可变长参数函数(Variable Argument Functions)” 来实现读取任意类型,数量的参数的。
printf
的函数原型是
int printf(const char* format,...);
而可变长参数函数的实际实现方式是将可变长部分(对应…部分),按照顺序,直接在内存中首尾相连的连接起来。
如 printf(“test %d %ld”,(int)1,(long)2);
此时 format
指向一段内存,开头是一个字符串,然后跟着一段int,随后是long
然而 printf
不知道他应该如何分别这些内存段,哪个是哪个(字符串可以用\0来找),所以这个时候就需要程序猿在提供 format
字符串的时候,同时提供随后参数列表中参数的对应长度!因而 %d
、%ld
等的混用会导致 printf
使用错误的长度去读取数据!严重的话会造成溢出,轻微的话会把数据读乱。
而cpp中提供了自定义的类转换,因此在cout<<
的时候,其实cout
接受的是string
,转换已经自动发生了,因而没有区别。
作者:BetaCat
链接:https://www.zhihu.com/question/283460749/answer/432742267
来源:知乎
解决方案
先进行类型转换,再使用 printf
输出。