建议老师们将本文收藏,待学生的需要时发给学生,免费口舌。
本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频
在C++里,我们使用cout进行控制台文本输出。这在学习编程的阶段很常用,但在真实的工作场合却极少使用,毕竟大部分的应用程序都是基于图形界面,而不是终端的。甚至,在C/C++的某些应用场合,比如单片机编程里,嵌入式设备甚至连屏幕都没有。
考虑到部分OJ系统中的在线编程题可能对输出格式作出精细要求,这里我们对cout控制输出进行“详细”讨论:包括cout的基本工作原理,以及通过cout进行精细格式输出的方法。
对工作原理不感兴趣,只想快速知道HOW的有编程经验的读者请直接阅读本文的第6部分。
1. cout基本工作原理
下述代码可以帮助我们理解通过cout的插入操作符(insertion operator<<)进行控制台文本输出的基本原理。
//Project - COUT
#include <iostream>
using namespace std;
int main() {
cout << "pi = " << 3.14159 << endl;
operator<<(cout,"pi = ").operator<<(3.14159).operator<<(endl);
return 0;
}
上述代码的执行结果为:
pi = 3.14159
pi = 3.14159
在iostream头文件中,很容易找到cout的定义。cout是一个类型为ostream的对象,其被连接到了标准输出流,即控制台。
extern ostream cout; /// Linked to standard output
上述程序的第6行与第7行完全等价。相关代码的执行过程如下:
- cout << “pi = “的实质是执行了一个名为operator<<( )的函数,其中,第1个参数是cout对象,第2个参数是”pi = “。这个函数把第2个参数的字符串输出到第1个参数所代表的控制台中。同时,该函数返回了cout的引用作为函数执行的结果。
- … << 3.141519则以前述函数调用所返回的cout引用作为基础,执行其成员函数operator<<( )。该成员函数存在多个函数名重载的版本,其中一个版本接受一个double作为参数,并将double的值输出到cout。同样地,本次函数调用也返回了cout的引用作为结果。
- 类似地,… << endl同样对应cout.operator<<( )函数的一次执行,该成员函数的一个重载版本接受endl作为参数,并向cout所代表的控制台输出一个换行符。
<<操作符在C语言里用作左移位操作,C++的标准模板库通过定义与该操作符“同名”的函数,扩展了该操作符的功能:向cout输出对象内容。
总结:iostream定义了多个重载的operator<<()操作符函数,这些不同版本的函数接受不同类型的参数,包括int, char, float, double, const char*, string等,并将这些参数对象转换成字符串,并输出到控制台屏幕上。
2. 改变进制
//Project - HexOct
#include <iostream>
#include <stdio.h>
using namespace std;
int main(){
int b = 0x17; //十六进制 hexadecimal
int c = 017; //八进制 octal
int d = 0b01111110; //二进制 binary
cout << "0x17 = " << b << ", 017 = " << c << ", 0b01111110 = " << d << endl;
printf("17: %x, %d, %o\n", 17, 17, 17);
cout << "17: " << hex << 17 << ", " << dec << 17 << ", " << oct << 17 << endl;
hex(cout);
cout << "17: " << 17 << ", ";
dec(cout);
cout << 17 << ", ";
oct(cout);
cout << 17 << endl;
return 0;
}
上述代码的执行结果为:
0x17 = 23, 017 = 15, 0b01111110 = 126
17: 11, 17, 21
17: 11, 17, 21
17: 11, 17, 21
上述代码可以看出,通过执行cout << hex,可以改变cout的内部状态,使用在后续输出数值时使用16进制。cout << dec (十进制),cout << oct (八进制)同理。
事实上,这里的hex, dec, oct是一种被称之为操作算子(manipulator)的特殊函数。下述3行代码事实上等价:
cout << hex;
cout.operator<<(hex);
hex(cout);
在ios_base.h中我们可以找到hex()函数的定义:
inline ios_base&
hex(ios_base& __base)
{
__base.setf(ios_base::hex, ios_base::basefield);
return __base;
}
在形式上,cout << hex被解释成多轮函数调用,首先是:
cout.operator<<(hex);
这个被重载的operator<<()函数将hex函数名当成一个函数指针,然后通过这个函数指针调用hex()函数:
hex(cout);
而hex()函数又通过cout的setf()函数发挥作用。读者或许会疑惑说,这么多层的函数调用是否会降低代码的执行效率,事实上,由于相关函数多是内联(inline)的,编译器的优化会消除这些“形式”上的不必要的函数调用。
3. 输出宽度控制
#