VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 1414|回复: 3

C++中 printf 和 cout 的区别

[复制链接]
admin 发表于 2017-8-10 15:47:52 | 显示全部楼层 |阅读模式
最近给大家更新《实用C++》系列教程的时候,有网友问:cout 和 printf 有什么实质性的区别吗?@2017666

这里给大家找到了两篇不错的博文,转载过来,希望对大家有帮助!


文章一:printf 和 cout 的区别详述
转载自:http://blog.csdn.net/ysayk/article/details/50959909

首先看C++中常见的输出格式:
  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     cout<<"Hello,World!";
  6.     return 0;
  7. }
复制代码


  我们在C中学习的标准输入输出的方法是借助输出函数printf和scanf,但是在C++中我们经常用cout和cin来进行输出和输入。cout看上去并不像一个函数,在C++的大趋势下,用printf和scanf显得格格不入,而且似乎也并不能理解为什么要用位计算符来进行输入输出字符的分隔?而且我们在使用cin和cout的时候发现发现它们在进行标准输入输出的时候<<和>>的用法有点类似于运算符,因为本身<<和>>是双目运算符,在进行标准输出和输出的时候我们如果当做运算符理解的话,的确就像一个双目运算符一样,左右量变的参数一个都不能少,实际上,在后续对于运算符重载的学习中,发现实际上cout和cin以及cerr其实都是运算符重载的结果。
  因为实际上是运算符重载的结果,所以我们不妨看下面的符合运算符重载逻辑的代码,如下:

  1. #include<iostream>
  2. using namespace std;
  3. intmain()
  4. {
  5.     cout.operator<<("Hello,World!");
  6.     cout.operator<<(endl);
  7.     return0;
  8. }
复制代码


  再进行编译运行,结果与标准的cout没有任何区别,实际上对于上面的代码就更好理解了,cout实际上是一个iostream类的对象,每次调用的时候就会输出对应的字符串,调用的实际上就是成员运算符函数operator<<,当然这里还有一个问题就是:为什么实际上我们的cout可以接受不同类型的数据并进行输出呢?
  原因也很简单,就是因为我们在重载运算符的时候,也重载了多个该函数,因为标准库的作者们早就为使用者定制了iostream::operator<<对于各种C++基本数据类型的重载版本,这才使得我们在使用的时候变得如此地方便。
  那么既然我们已经看出了cout的实质,不妨写一个cout的简化版,这里就抛弃了iostream,而用stdio来实现,因为是简化版,所以就仅仅写两个函数,一个是针对int,一个是针对于字符串。

  1. #include<stdio.h>
  2. class MyOutstream  
  3. {
  4. public:
  5.     const MyOutstream& operator<<(int value)const;//对整型变量的重载
  6.     const MyOutstream& operator<<(char*str)const;//对字符串型的重载
  7. };
  8. const MyOutstream&MyOutstream::operator<<(int value)const
  9. {
  10.     printf("%d",value);
  11.     return*this;//注意这个返回
  12. }
  13. const MyOutstream&MyOutstream::operator<<(char*str)const
  14. {
  15.     printf("%s",str);
  16.     return*this;//同样
  17. }
  18. int main(){
  19.     MyOutstream myout;//定义一个myoutstream的对象myout
  20.     int a=2003;    
  21.     char *myStr="Hello,World!";    
  22.     myout<<a<<myStr;
  23.     return 0;
  24. }
复制代码


  我们的mycout已经能完成一些工作了,但是我们观察上面的重载函数不难发现,重载函数最后都返回到了this,为什么?而且我们发现我们的mycout和标准的cout一样居然都可以实现连续地输出,其实这就是this指针的作用,在完成一次输出之后返回this指针,因为在这里方法是藏在已经实例化的对象中,所以返回this指针,后面就可以连续输出。
myout< <
  我们都知道,在printf中的\n可以实现一个换行,但是在C++中教程总是有意无意地让我们使用endl,两者看上去似乎一样,但是真的一样吗?
  实际上是不同的,endl实际上是一个操纵符,不仅仅实现了换行的操作,而且还对输出缓冲区进行刷新(使用缓冲区的原因是为了减少硬盘灯存储设备的读写次数),实际上,对于每一个输出流,都管理一个缓冲区(也就是说在系统中是存在多个缓冲区的),比如说下面这一行代码:

  1. os<<"please enter a value:";  
  2. //文本串可能被打印出来,也有可能被操作系统保存在缓冲区中,随后再打印。  
复制代码



  有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作,(在系统中,很多读写操作并不是一定都会输出,而是存储在缓冲区上的,由于设备的写操作可能很耗时,因此允许操作系统将多个输出操作组合为单一的设备写操作可以带来很大的性能提升。)
  那这里有一个问题,那我们很多的cout实际上是没有用endl或者flush等操纵符来主动清空缓冲区的,那么为什么还可以输出呢?
  其实,不仅仅是这些操纵符可以控制cout来清空缓冲区,实际上,有多种方法可以清空缓冲区:
  因为cout是行缓冲的,所以其实有以下几种方式(我们需要知道的是,下面任何会清空缓冲区的条件中都的确会导致输出,但是仅仅表明是在该条语句要清空缓冲区之间的某一时间点会导致输出,但是并没有说是具体什么时间点,具体时间点可能依据操作系统和具体编译环境而定):
   1、缓冲区满;
   2、用户手动刷新,即显示地清空,比如像上面的使用操纵符的方式;
   3、程序结束(这种情况非常常见),见下面例1代码;
   4、程序的下一步将要从标准输入流读入数据,则会将之前的缓冲区清空,见下面例2代码;
  实际上,endl是作为一个操纵符存在的,它不仅仅实现了换行操作,而且还对输出缓冲区进行了刷新,也就是说实际上,在本来的输出操作之后,endl在实现了换行的同时将缓冲区显式地清空了。

  1. //例1
  2. include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6.     int ch;
  7.     while ((ch=getchar()) != '\n' )
  8.     {
  9.         putchar(ch);
  10.         cout<<ch;
  11.     }
  12.     printf("\nbefore exit\n");
  13.     return 0;
  14. }
  15. /*如果主函数并没有结束
  16. int main()
  17. {
  18. int ch;
  19. while ((ch=getchar()) != '\n' )
  20. {
  21. putchar(ch);
  22. cout<<ch;
  23. }
  24. while (1){}
  25. return 0;
  26. }
复制代码

  1. //例2
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6.     int ch;
  7.     while ((ch=getchar()) != '\n' )
  8.     {
  9.         putchar(ch);
  10.         cout<<ch;
  11.     }
  12.     int a;
  13.     cin>>a;
  14.     while (1){}
  15.     return 0;
  16. }
复制代码


  我们已经明白缓冲区的存在本身就是为了减少硬盘等存储设备的读写次数的,但是在使用cout在屏幕上进行输出的时候,有时候似乎看起来是否清空对于程序本身区别也不是很大,但是实际上真的是这样吗?
  实际上,在对于文件的操作中,懂得如何去高效地利用缓冲区来处理数据是相当重要的,比如我们看下面的代码

  1. #include <fstream>
  2. using namespace std;
  3. int main () {
  4. ofstream outfile ("test.txt");
  5. for (int n=0; n<100; n++)
  6. {
  7.     outfile << n;
  8.     outfile.flush();//每次均清空缓冲区
  9. }
  10. outfile.close();
  11. return 0;
  12. }
复制代码


  我们可以看到很明显很简单的读写操作由于持续的缓冲区清空操作则会导致速度大部分下降,所以在大容量的文件进行读写的时,以我们通常是写入一定的字节数之后再进行刷新,一般如何操作呢?靠的就是这些操作符。
  最后总结,C++的iostream库和C中的stdio库中分别的cout/cin和printf/scanf相比有哪些优势呢?首先是类型处理更加安全,更加智能,我们无须应对int、float中的%d、%f,而且扩展性极强,对于新定义的类,printf想要输入输出一个自定义的类的成员是天方夜谭的,而iostream中使用的位运算符都是可重载的,并且可以将清空缓冲区的自由交给了用户(在printf中的输出是没有缓冲区的),而且流风格的写法也更加自然和简洁。


文章二:C++中 cout 与 printf 区别
转载自:http://blog.csdn.net/xiaohangwj/article/details/51597860

  1. # include <iostream>
  2. #include <iomanip>

  3. using namespace std;
  4. union endian
  5. {
  6. int data;
  7. char ch;
  8. };
  9. void main()
  10. {
  11. endian ed;
  12. ed.data = 0x12345678;
  13. if(ed.ch == (ed.data & 0xff))
  14. cout<<"The system is little dian."<<endl;
  15. else
  16. cout<<"The system is big dian."<<endl;
  17. for(int i=0;i<sizeof(int);i++)
  18. {
  19. printf("%#x--------%p\n",*(((char*)&ed.data)+i),((char*)&ed.data)+i);
  20. }

  21. cout.setf(ios::showbase | ios::uppercase);
  22. for(int i=0;i<sizeof(int);i++)
  23. {
  24. cout<<hex<<*(((char*)&ed.data)+i)<<"--------"<<hex<<((char*)&ed.data+i)<<endl;
  25. }
  26. for(int i=0;i<sizeof(int);i++)
  27. {
  28. cout<<hex<<(int)*(((char*)&ed.data)+i)<<"--------"<<hex<<(int)((char*)&ed.data+i)<<endl;
  29. }

  30. system("pause");
  31. }
复制代码


输出结果为:

The system is little dian.
0x78--------0012FF28
0x56--------0012FF29
0x34--------0012FF2A
0x12--------0012FF2B
x--------xV4烫烫

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

海浪_SeaWave 发表于 2017-8-13 20:38:37 | 显示全部楼层
然而尽管更安全、更智能,在算法竞赛当中一般不推荐使用cin、cout,原因很简单——太慢了。
事实上,甚至有时候连printf\scanf都很慢,必须要用putchar、getchar一个一个字符输出。

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

2017666 发表于 2017-8-15 01:38:50 | 显示全部楼层
学习了。。

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

besteast 发表于 5 天前 | 显示全部楼层
dddddddddddddddddddddddddddd

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入驿站

本版积分规则

展开

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号 )

返回顶部
x

VC驿站微信公众号cctry2009

GMT+8, 2017-12-13 22:43

Powered by Discuz!

© 2009-2017 cctry.com

快速回复 返回顶部 返回列表