cout输出流的执行顺序

2024-03-24 08:32
文章标签 输出 执行 顺序 cout

本文主要是介绍cout输出流的执行顺序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面是IBM的一道笔试题

#include <iostream> 
using namespace std; int fun( ) 
{ 
cout << "f" ; 
return 1; 
} 
int main() 
{ int i = 1; 
// cout << i++ << i++ << i++ << endl; 
cout << "m" << fun() << fun() << fun() << endl; 
return 1; 
} 

输出fffm111
问题:cout这种连接写法的输出的执行顺序是啥呢?

cout<<"m"<<fun1()<<fun2()<<fun3()<<endl;
<<运算是左结合的。
必然先求cout<<”m”的值,值仍然是cout
然后试图求cout<< fun1()的值,这必须先求出fun1()的值。整个表达式的值仍然是cout
然后试图求cout<< fun2()的值,这必须先求出fun2()的值。整个表达式的值仍然是cout
然后试图求cout<< fun3()的值,这必须先求出fun3()的值。整个表达式的值仍然是cout
最后是cout<< endl的值,值是cout
整个表达式语句以分号结尾
注意:问题就在这里:“这必须先求出fun1()的值”,“这必须先求出fun2()的值”,“这必须先求出fun3()的值”,这3句。这是计算<<运算的前提。只要分别在计算cout<< fun1(),cout<< fun2(),cout<< fun3(),之前完成就可以了。
因此,具体是先计算fun1()的值,还是先计算fun2()的值,还是先计算fun3()的值,还是先计算cout<<”m”的值,都不影响表达式的值。
问题就在这里:
这是个<<表达式。<<本来是位运算,但是这里cout却是来利用运算的“副作用”。
所谓副作用,就是计算一个表达式的时候,除了得到它的值以外,对环境产生的影响都是副作用。
比如:

int a=1,b=2,c=3,d; d=a<<b:
这一步,a<

int foo(int a, int b) { return a+b; } 
int bar(int a, int b) { return a-b; } 
int a=1,b=2,c=3,d; 
d=foo(a,b)+bar(b,d); 

这里,foo()和bar()都没有副作用。因此,这个表达式,不论是先计算foo(a,b)的值,还是先计算bar(b,c)的值,都不会影响计算的结果。
但是,如果是这个例子:

int foo(int* a) { (*a)++; return *a;} 
int bar(int* a) { (*a)--; return *a;} 
int a=5,b; 
b=foo(&a)+bar(&a); 

这个表达式,foo()和bar()都有副作用,所以,先计算foo(&a)还是先计算bar(&a),将直接影响到b的值。
假如先计算foo,再计算bar。
首先,a=5
计算foo(&a),a变成6,foo(&a)的值是6
计算bar(&a),a变成5,bar(&a)的值是5
这样,b=6+5=11
假如先计算bar,再计算foo。
首先,a=5
计算bar(&a),a变成4,foo(&a)的值是4
计算foo(&a),a变成5,bar(&a)的值是5
这样,b=5+4=9
这就造成了计算结果不一致。
===
那。。。怎么办
一般来说,编c/c++程序有一个纪律:一个语句中不要有两个表达式有副作用。
典型的这类行为包括:b=(a++)+(a++)+(a++);
这是典型的违反这条纪律的行为。每个a++都有副作用(改变a的值)。整个表达式的值跟求值顺序直接相连。
还有就是

char* fun() { cout<<"q"; return ""; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; 

每个fun()都有副作用(向屏幕上显示字符)。因此效果直接与求值顺序相关。(而整个表达式的值我们根本就不关心。虽然我知道,值就是cout)。
======

在c/c++中,求值顺序是怎么样的?

不知道。

C/C++的规范中,求值顺序是不规定的。这是为了给编译器以优化的空间。

比如:

b=(a+2)+(a+2);,那么如果只计算一次a+2的值,而不是两次,那么计算量会大大降低。

因此,

不要在C语言里面做这种事情:

char* fun() { cout<<"q"; return ""; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; 

要这样:

char* fun() { return "q"; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 

这样更好:

string fun() { return string("q"); } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 

这样就更好了:

string f="q"; // 隐式转换 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 

这应该只是个测验。我相信IBM的软件工程师们不会编出这种垃圾代码的。

代码稍微修改了下

#include <iostream> using namespace std; int fun(int i) 
{ cout << "f"<<i; return i; 
} 
int main() 
{ int i = 1; cout << i++ << i++ << i++ << endl; cout << "m" << fun(1) << fun(2) << fun(3) << endl; cin.get(); return 1; 
} 

输出结果:
321
f3f2f1m123

如果只针对题来说的话,实际是这样的
cout<<”m”<

这篇关于cout输出流的执行顺序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/841027

相关文章

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

java中ssh2执行多条命令的四种方法

《java中ssh2执行多条命令的四种方法》本文主要介绍了java中ssh2执行多条命令的四种方法,包括分号分隔、管道分隔、EOF块、脚本调用,可确保环境配置生效,提升操作效率,具有一定的参考价值,感... 目录1 使用分号隔开2 使用管道符号隔开3 使用写EOF的方式4 使用脚本的方式大家平时有没有遇到自

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

一个Java的main方法在JVM中的执行流程示例详解

《一个Java的main方法在JVM中的执行流程示例详解》main方法是Java程序的入口点,程序从这里开始执行,:本文主要介绍一个Java的main方法在JVM中执行流程的相关资料,文中通过代码... 目录第一阶段:加载 (Loading)第二阶段:链接 (Linking)第三阶段:初始化 (Initia

JAVA实现亿级千万级数据顺序导出的示例代码

《JAVA实现亿级千万级数据顺序导出的示例代码》本文主要介绍了JAVA实现亿级千万级数据顺序导出的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 前提:主要考虑控制内存占用空间,避免出现同时导出,导致主程序OOM问题。实现思路:A.启用线程池

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Java实现远程执行Shell指令

《Java实现远程执行Shell指令》文章介绍使用JSch在SpringBoot项目中实现远程Shell操作,涵盖环境配置、依赖引入及工具类编写,详解分号和双与号执行多指令的区别... 目录软硬件环境说明编写执行Shell指令的工具类总结jsch(Java Secure Channel)是SSH2的一个纯J

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作