C++中的cout计算顺序和输出顺序问题(已解决)

2024-04-27 15:58

本文主要是介绍C++中的cout计算顺序和输出顺序问题(已解决),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++中cout的输出问题及个人疑问

前段时间遇到一个困惑,在C++语言中cout输出的顺序问题及在不同IDE中有不一样的结果(VS跟Dev),以下前面都是在vs2015之中运行,最后的猜想在Dev中运行。

以下是源代码:

#include "stdafx.h"
#include<iostream>
using namespace std;
static int a[] = { 1,3,5,7,11,13 };
int main()
{int *p;p = a + 3;cout << *p << " " << *(p++) << endl;cout << *(p - 2) << " " << *(a + 4) << endl;
}

图例说明↓:
a的首地址是a[0],对应的值是1,执行a+3之后,变成a[3]

在没有搞明白cout输出流的执行顺序之前,我以为结果是这样的↓:

    7    75   11

 首先*p指向a[3]的值,等于7,接着执行 *(p++),由于++是后置式自增运算符,p先自增,结果在下一步体现,即 *(p++)=7;接着第二行输出, *(p - 2)在上一行*(p++)自增之后,应指向a[4],p-2之后指向a[2],即值为5,最后*(a + 4)指向a[4],值为11.然而,结果却是这样的↓:

运行结果
##再重复验证几次,甚至搬到舍友电脑上运行之后发现结果一样,因此不禁产生疑问,是不是C++中cout的输出顺序不是正常的从左往右呢?
通过网上百度和参考了众多博主的文章之后发现:
cout的输出顺序和执行顺序不一样!
计算顺序:从右往左
输出顺序:从左往右

对结果的再次分析

首先第一行cout  *p , *(p++) ;于两个cout放在同一行,cout里面包含运算,因此先从右往左开始计算*(p++),由于是后置式的自增,值仍是等于7,但下一步的自增之后值变成11,也就是*p等于11,第一行从左往右输出*p跟*(p++)结果就是11,7;第二行cout *(p - 2) , *(a + 4),从右往左计算*(a+4),值等于11,*(p-2),第一行p自增再减2,则p指向了a[2],值等于5,从左往右输出的结果就是5,11.

因此最终结果:

11  7
5   11

验证

既已得知了cout的计算顺序跟输出顺序,想着继续验证一下
还是原来的代码,但cout变了一下

#include "stdafx.h"
#include<iostream>
using namespace std;int a[] = { 1,3,5,7,11,13 };
int main()
{int *p;p = a + 3;//cout << *p << " " << *(p++) << endl;cout << *p << " " << *(++p) << endl;cout << *(p - 2) << " " << *(a + 4) << endl;
}

如没意外,结果应为
11 11
5 11

结果

验证猜想

接着验证

#include "stdafx.h"
#include<iostream>
using namespace std;int a[] = { 1,3,5,7,11,13 };
int main()
{int *p;p = a + 3;//cout << *p << " " << *(p++) << endl;//cout << *p << " " << *(++p) << endl;cout << *p << " " << *(p+1) << endl;cout << *(p - 2) << " " << *(a + 4) << endl;
}

从右往左计算*(p+1)等于11,由于p+1没有给p重新赋值,则p还是等于7;第二行从右往左计算(a+4)等于11,*(p-2)指向a[1],等于3;输出结果应为:
7 11
3 11

结果

验证

问题的延申

cout两个的结果皆符合猜想,那么四个的顺序是否一样呢?

#include "stdafx.h"
#include<iostream>
using namespace std;int a[] = { 1,3,5,7,11,13 };
int main()
{int *p;p = a + 3;//cout << *p << " " << *(p++) << endl;//cout << *p << " " << *(++p) << endl;//cout << *p << " " << *(p+1) << endl;//cout << *(p - 2) << " " << *(a + 4) << endl;cout << *p << " " << *(p++) << " " << *p << " " << *(p++) << endl;
}

分析

按照从右往左的计算顺序,却分析出了两种可能性。
其一:
从右往左先计算*(p++),值等于7,自增,下一步 p值等于11,再下一步 * (p++),值等于11,自增,最后一步p值等于13;所以从左往右的输出是13 11 11 7
其二:
从右往左计算*(p++),值等于7,自增,下一步的*p没有计算,先跳过到下一步的 *(p++),值等于11,自增,*p等于13,所以从左往右的输出是 13 11 13 7

运行结果

第二种
结果看起来是第二种,也就是cout从右往左严格按照先计算的原则,再从左往右输出结果。
然而,在Dev上运行的结果却不一样
Dev
第一种
结果却是符合第一种猜想

是不是因为不同IDE的产生的结果不一样呢?
(ps:前面cout两个的时候Dev结果跟VS一致)

解决:学了编译原理之后,发现,对语义的不同理解可以得到不同的编译程序,除此之外,不同版本的编译系统翻译出来的结果也可能不同,也不能说哪个是对的哪个是错的,唯一可以确定的是p++的自增规则没有变化,但由于是不同编译器的原因,对语义也产生了不同的理解,因此结果并不一样。

这篇关于C++中的cout计算顺序和输出顺序问题(已解决)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

MySQ中出现幻读问题的解决过程

《MySQ中出现幻读问题的解决过程》文章解析MySQLInnoDB通过MVCC与间隙锁机制在可重复读隔离级别下解决幻读,确保事务一致性,同时指出性能影响及乐观锁等替代方案,帮助开发者优化数据库应用... 目录一、幻读的准确定义与核心特征幻读 vs 不可重复读二、mysql隔离级别深度解析各隔离级别的实现差异

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

java -jar example.jar 产生的日志输出到指定文件的方法

《java-jarexample.jar产生的日志输出到指定文件的方法》这篇文章给大家介绍java-jarexample.jar产生的日志输出到指定文件的方法,本文给大家介绍的非常详细,对大家的... 目录怎么让 Java -jar example.jar 产生的日志输出到指定文件一、方法1:使用重定向1、

Java报错:org.springframework.beans.factory.BeanCreationException的五种解决方法

《Java报错:org.springframework.beans.factory.BeanCreationException的五种解决方法》本文解析Spring框架中BeanCreationExce... 目录引言一、问题描述1.1 报错示例假设我们有一个简单的Java类,代表一个用户信息的实体类:然后,

Python中经纬度距离计算的实现方式

《Python中经纬度距离计算的实现方式》文章介绍Python中计算经纬度距离的方法及中国加密坐标系转换工具,主要方法包括geopy(Vincenty/Karney)、Haversine、pyproj... 目录一、基本方法1. 使用geopy库(推荐)2. 手动实现 Haversine 公式3. 使用py

Linux部署中的文件大小写问题的解决方案

《Linux部署中的文件大小写问题的解决方案》在本地开发环境(Windows/macOS)一切正常,但部署到Linux服务器后出现模块加载错误,核心原因是Linux文件系统严格区分大小写,所以本文给大... 目录问题背景解决方案配置要求问题背景在本地开发环境(Windows/MACOS)一切正常,但部署到

MySQL磁盘空间不足问题解决

《MySQL磁盘空间不足问题解决》本文介绍查看空间使用情况的方式,以及各种空间问题的原因和解决方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录查看空间使用情况Binlog日志文件占用过多表上的索引太多导致空间不足大字段导致空间不足表空间碎片太多导致空间不足临时表空间

Mybatis-Plus 3.5.12 分页拦截器消失的问题及快速解决方法

《Mybatis-Plus3.5.12分页拦截器消失的问题及快速解决方法》作为Java开发者,我们都爱用Mybatis-Plus简化CRUD操作,尤其是它的分页功能,几行代码就能搞定复杂的分页查询... 目录一、问题场景:分页拦截器突然 “失踪”二、问题根源:依赖拆分惹的祸三、解决办法:添加扩展依赖四、分页