【C++】数据类型、函数、头文件、断点调试、输入输出、条件与分支、VS项目设置

四、基本概念

这部分和C语言重复的部分就简写速过,因为我之前写过一个C语言的系列,非常详细。C和C++这些都是一样的,所以这里不再一遍遍重复码字了。感兴趣的同学可以翻看我之前的C语言系列文章。  

1、数据类型
编程的本质就是操作数据。
操作数据就是读数据、进行计算、写数据,其中读和写必然要牵扯到数据的存储。
数据的存储就必须要有数据的名字(变量名)、数据的内容(变量值)、数据的类型(变量类型)。

名字和值好理解,那为啥要类型呢?类型表示给这个变量一个多大的空间去存储它,比如一个字母a就给1个字节(8bit)就可以了,多了就是浪费;一个整数一般给4个字节,就是32位,当然你还可以规定比如第一个位表示符号位,这样就是可以表示正整数和负整数了,那剩下的31位,就能最大存一个2的31次方这个数字,当然如果你存了31个0,那就是0了,如果你存了31个1,那就是数字2的31次方了。也所以不是你想存多大就能存多大的,数字超过2的31次方,就会发生溢出,也就是你存的数字并不是你想存的数字了。

所以数据类型就是指这个数据存放空间的大小。不同的数据类型意味着占用不同大小的内存空间。

下图是基本的数据类型:

说明:
(1)数据首先是分为常量变量。在程序运行的过程中,其值不能被改变的叫常量。可以改变的叫变量,入上图F。
常量我们用宏定义,上图A,宏URL就表示字符串“hello world”。上图中BCDE都是变量。

(2)不管是常量还是变量,对计算机来说最重要的是地址和类型!所谓的变量名其实是给程序员看的。计算机只要知道这个数据的首地址和占用内存的大小即可,它不需要知道这个数据的名称。数据名称只是程序员写的代码和编译器之间的沟通信号。编译器和代码用变量名沟通完毕后,编译器再和cpu传话时,用的就是这个数据的首地址和占用空间了。

(3)如果是整数变量,你可以定义变量的类型为int,short,long,long long这4种类型之一。其中int类型占用4个字节,short类型占2个字节,long类型占4个字节,long long 类型占8个字节。占用字节的大小决定着你这个数字在内存中的存储空间的大小,也就是决定着你存储的数字的上下限。unsigned表示是否有符号位。
同理其他数据类型。

(4)不同的数据类型给分配多大的内存,一般是取决于编译器,不同类型编译器之间会有差异,一般情况下,不会相差太大。

(5)bool类型不是取1就是取0,是不是1个比特位就够用了,为啥给分一个字节的空间呢?因为我们寻址内存的是是按照字节寻找的,找不到位的哈。

(6)除了上面展示的数据类型,你也可以创建自定义数据类型,但你自定义的类型都是在这些基本类型之上创建的。

(7)数据转化为指针或引用。指针通过一个*号来声明,引用用&表示。说来话长,这些以后要专门聊。

2、函数

函数就是我们写的代码块,被设计用来执行特定的任务。
如果函数被放到类里面了,就叫做方法了。所以这里我们讲的是函数不是方法。
为啥要函数?避免重复写相同的代码。你就理解为把某项特定的功能封装起来。你啥时候想用这个功能了,你调用这个函数就可以了。下面用例子展示:
左图所示:我写了3个函数A、B、C。函数A的名字是Multiply,名字前面的int表示函数的返回值的类型是整型,名字后面的括号里是参数。这个函数有两个参数,a和b,参数a和b的类型都是int类型。函数B的名字是func,这个函数只是要实现在屏幕上打印一个4x2的结果,所以也不需要什么参数,所以小括号里面啥参数也不用写。又因为这个函数也不返回啥,所以函数名前面的返回值类型是void,void就是啥也没有的意思。函数C就是我们常说的main函数,是一个程序的入口函数,因为不需要传入任何参数,所以后面小括号里面啥也不用写,又因为其返回值是0,所以main前面是int。
左图的Multiply函数就是一个“实现两个数相乘计算出结果”这个功能的函数。我们在C函数体内调用了3次Multiply函数。但是有没有发现,在main函数里写了3遍cout,是不是很麻烦。所以右图我们再写一个MutiplyAndLog函数,把A和B的功能都包含进来,是不是右图的main函数就简洁了很多!对这就是函数的封装打包,就是为了避免重复写代码!

函数有声明定义声明通常存储在头文件中,我们在翻译单元或cpp文件中编写定义

函数很重要,每个程序都是由一系列函数组成的。所以这里简单过一下函数调用过程中的堆栈

堆(Heap)与栈(Stack)是开发人员必须面对的两个概念,不同场景下,堆与栈代表不同的含义。一般情况下,有两层含义:
(1)程序内存布局场景下,堆与栈表示两种内存管理方式;
(2)数据结构场景下,堆与栈表示两种常用的数据结构。

这里的堆栈通常称为调用栈或执行栈,是由操作系统和编译器共同管理的一种数据结构,用于存储函数调用的上下文信息。下面展示一个函数调用的粒子:

可见一个程序的运行一般是在内存中跳来跳去执行函数的。函数的prologue、epilogue是自动由编译器生成的,它的具体实现细节可能因编程语言、编译器、目标架构和调用约定的不同而有所变化。例如,在x86架构的C语言中,函数prologue和函数 epilogue 的典型汇编代码可能如下:

3、头文件

头文件通常用于声明一些函数。头文件中有很多函数声明,使我们在多个.cpp文件中使用。头文件就是我们声明函数的一个公共地方。

如上图所示,如果每个.cpp文件用到的函数都得声明一下,就非常麻烦,所以我们所有的函数的声明都放到.h文件中,然后在.cpp中include这个头文件,当预编译时就相当于是声明了。
A:这条语句的意思是只声明一次。当我们有多个头文件时,很难保证多个头文件中的声明函数没有重复的,当我们把多个头文件都include到.cpp文件中时,就会出现重复声明,就会报错,pragma once可以避免多次声明。
B:有的有头文件有后缀.h,有的头文件没有后缀,这是因为C++标准库和C标准库的区分。C++标准库的头文件文件名都没有扩展名,以此和C标准库进行区分。
C:include头文件时,有的用尖括号有的用双引号是因为:尖括号只用于编译器包含的默认路径,而如果你使用引号,那就自由很多,你可以写任意的你的相对路径。

4、断点调试

如果你的代码有语法错误,那编译时就会报错,你按照报错信息调试代码即可。但是如果你的代码能顺利运行但就是运行结果非你所想、或者运行过程中系统崩溃等现象,这些你就没法通过报错信息调试了,此时很重要的调试方法就是打断点->读取内存信息,去分析为啥运行过程中没有按照你的预期执行。

设置断点是为了读取内存。断点就是暂停的意思,程序执行到断点处就会挂起执行线程,此时程序的状态,就是你内存的状态。此时你查看内存视图,诊断你程序出问题的原因。

(1)如何进入断点调试模式:

(2)内存查看的基本操作:

以上就是打断点,读取内存的方法。断点调试的内容很深很深,这里只是入门展示一下。

5、输入输出

(1)C与C++的输入输出方式对比
输入输出是人机交互的最直接方式,我们以后会经常用到。为了防止有些学过C的同学混淆,我们先区分一下C与C++的输入和输出。

我们先看输入
C用的函数是scanf(),我这里用scanf_s是因为我用的是C++编译的,会报这个函数更新了,让我用scanf_s替代,这没关系。
我们看scanf_s函数,函数第一个参数:它是一个包含占位符的字符串,后面的参数是这些占位符的地址,&是取址符
函数的返回值是成功赋值的数据个数。
说明:当程序执行到scanf_s时,程序就停止在控制台,等待用户输入。用户一定要按照A数字B数字C数字的方式输入,也就是第一个参数规定的格式。当然如果你第一个参数没有规定格式,那scanf就默认是用回车分隔abc三个变量的。

C++用的是cin是iostream类的一个实例,程序运行到B2时也是会停止在控制台等待用户输入,默认用回车分隔用户的输入内容。
其中>> 是流提取运算符。C++ 编译器会根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。所以使用C++的输入输出,你就不需要老考虑使用哪个占位符了,这就方便了很多!

我们再看输出
一个用的是printf,一个用的是cout。printf函数也用到占位符;cout用到<<流插入运算符
C++ 编译器会根据要输出变量的数据类型,选择合适的流插入运算符来显示值。流插入运算符 << 被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项。
endl表示换行符

最后看看占位符
占位符是一种有特定作用的符号,用于在格式化字符串中占住一个固定的位置,之后填充。占位符也分为输入占位符和输出占位符。
输入占位符的一般格式为:%[*][输入数据宽度][长度]类型, 其中有方括号[]的项为非必选项
输入占位符中[*]表示该输入项读入后不赋予相应的变量,即跳过该输入值。

输出占位符的一般格式为:%[标志][输出最小宽度][.精度][长度]类型, 其中有方括号[]的项为非必选项
输出占位符中[.精度]表示如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数

下面举个小例子:

(2)C++的输入输出功能
C++的输入输出功能是由输入输出流(iostream)库提供的。iostream是标准库的一部分。
输入输出流是一个类层次结构。
标准输入standard input与预定义的iostream对象cin绑定在一起。
标准输出standard output与预定义的iostream对象cout绑定在一起。
标准错误standard error与预定义的iostream对象cerr绑定在一起。

输出操作符<<用来将一个值导向到标准输出cout或者标准错误cerr上。

双字符序列"\n"表示换行符newline。这是显式的进行换行,还可以使用预定义的iostream操纵符endl。
操纵符endl是在iostream上执行的一个操作:在输出流中插入一个换行符,然后刷新输出缓冲区。
类似,输入操作符>>用来从标准输入读入一个值

下面示例一个读取未知个数的输入值:

(3)文件的输入输出
示例:从origin.txt文件中读取数据,写入到input.txt文件中:

6、条件与分支
说明:本部分不讲条件语句本身,因为if语句本身是非常好理解的,就是if条件成立就执行下面的代码块,if条件不成立就跳过,这些条件语句我在C语言系列有详细的讲解,不明白的同学可以翻看那部分。这里我主要是深挖一下条件语句底层的实现逻辑:

几个概念:条件语句conditioan、if语句、分支语句branch

我们写if语句时,是先对实际condition(条件语句)进行评估,然后才是基于评估后的branch(分支语句)。

当我们开始一个应用程序时,整个应用程序及其所有模块加载到内存中。所以这些所有的指令组成了我们的程序,而且都被存储在内存中。当程序中有很多条件语句所产生的分支,基本上就是告诉cpu跳到这部分执行,再跳到那部分执行。这种在内存中跳来跳去的执行,实际上其过程是非常复杂的。比如cpu得先检查条件,然后跳到内存的不同地方,然后从那里开始执行指令。这意味着if语句和分支通常有比较大的开销。如果你想让你的代码快,最好少使用if语句。实际上很多优化的代码其实是特意避开分支的,是特意避免使用if语句。

下面我们看看一个分支的运行过程:

A:==是equality运算符, ==能工作是因这个运算符在C++标准库中被重载了。直白点说,就是C++标准库中有一个equality函数,这个函数接受两个整数参数,这个函数的功能是检查这个两个整数参数的内存(就是取这两个参数的四个字节的内存,前面不是说过整数一般都是4个字节嘛)以确保它们是相等的(就是比较这个两个4个字节的每一位,就是总共32位,看看这32位,是否每一位都是相等的,只有32位全部相等才相等),如果相等返回true,不相等返回false。

同理,你在C和C++中看到的所有的这些操作符都一个道理,都是在标准库中有确定的应用方式。

这里是先执行x==5,也就是先检验x是否等于5,如果x等于5就返回true,否则返回false

下面我们再通过反汇编视图(disassembly视图),看看编译器实际生成的if语句的汇编代码:

这里汇编代码我可能讲不了,就说几个点吧:
cmp:comparasion
jne:jump not equal
mov:move
je:jump equal 条件跳跃

(1)我们前面说过bool类型占用的是一个字节(byte),但是一个字节里面有8位(bit),而bool只需要1位就可以表示了,那编译器如何在一个byte中寻找那个bit的呢?结论是:只要这8位中有一位是1,那就是true;如果8位全部为0才是false。

(2)if汇编语句中第一行就是将变量ComparisonResult的值加载到寄存器eax。
第二行test是测试条件,看eax寄存器是否是能通过条件,就是是否是true,就是是否有1。也就是对这两个寄存器进行逻辑与计算。
逻辑计算完毕后开始执行第三行je,je是条件跳跃,如果test的结果是True,就一行一行往后继续执行,后面就是Log函数;如果test的结果是false,就是跳转到后面的地址执行。

(3)上面的反汇编视图是我们在调试(debug)模式下的汇编代码,所以编译器实际上是一点都没有优化我们的代码,所以我们可以回头看代码的运行机制。其实编译器在编译的时候是要进行优化的。
所谓优化,实质上是对代码进行等价变换,使得变换后的代码运行结果与变换前的代码运行结果相同,而运行速度加快或占用存储空间减少,或两者都有。

具体我们这里的if语句,编译器其实在if语句前都已经知道if语句中的条件是否成立,因为前面不是有int x = 5嘛,编译器都知道变量x的值是5,所以x等不等于5,编译器是知道的,所以bool变量ComparisonResult是0还是1,编译器也是知道的。所以在实际的编译过程中,编译器直接把if(false)下面的代码块直接就删除了。这点我们在讲编译预处理部分的时候也讲过。而不需要程序已经到执行阶段了,再去比较x等不到5,ComparisonResult是true还是false。

那预编译阶段,编译器是如何做到比较的呢?我们知道两个整数相等还是不相等,就是所谓的常数折叠,就是编译器其实在执行int x=5时,并不是给变量x分配一个首地址+4个字节的长度,而是把x = 5保存到符号表里,在用到x时,会根据符号表把x替换成1。同理,编译器再执行bool ComparisonResult = x == 5;时,也不会给变量ComparisonResult分配一个自己去存储0或1,也是保存在符号表中。也所以预编译阶段编译器就知道x和5的比较结果了,也就是ComparisonResult的值了。所以预编译阶段if语句中的不符合条件的分支代码块就已经被直接删掉了。if后面跟的分支语句都是满足if条件需要执行的语句,这样就减少程序执行过程中的计算量了。

所以如果我们想调试自己的程序时,你尽量关闭所有的优化,最好就是处于debug模式下。

(4)if语句的写法
也所以我们上面例子中的if语句只要写if(ComparisonResult)即可,其实是不用写if(ComparisonResult==true)或if(ComparisonResult==1)。而且即使如果你这样写了,编译器也不会给你真正编译成,让你再去调用标准库中equality函数,再去对比一下ComparisonResult和1是否相等这个操作。
也所以,上面的代码你还可以简写成下图1的形式:

7、VS项目设置

在Visual Studio我们创建项目的步骤如下:

但是Visual Studio的这种项目组织方式不是很合理。项目组织就是设置你的各种文件目录。一个清晰明了的目录可以使你的项目一目了然。我们通常的做法是:创建一个名为Source或者src的文件夹,这个文件夹包含我们所有的源代码、头文件等东西,这样可以使我们的项目文件和可能使用到的任何其他资源,能够被很好的分开在不同的文件夹中。下面我们更改这种组织方式:

工必善必先利其器,这里先介绍一下VS的设置,以后我们还会讲到编译器设置、链接设置、release模式优化设置等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/31582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零入手人工智能(4)—— 逻辑回归

1.小故事 一家金融科技公司&#xff0c;公司的首席执行官找到团队提出了一个紧迫的问题&#xff1a;“我们如何提前知道哪些客户可能会违约贷款&#xff1f;” 这让团队陷入了沉思&#xff0c;经过激烈讨论团队中的数据分析师提议&#xff1a;“我们可以尝试使用逻辑回归来预测…

基于51单片机的函数信号发生器

基于51单片机函数信号发生器 &#xff08;仿真&#xff0b;程序&#xff0b;原理图&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.LCD1602液晶显示波形种类和频率值&#xff08;10-100HZ&#xff09;&#xff1b; 2.按键设置波形种类和设定频率步进值…

UE5近战对抗系统Tutorial

文章目录 BP_Character 组合攻击Notify State 检测攻击BP_Character 攻击反馈BP_Character 生命系统BP_Character 死亡效果BP_Character 武器系统BP_Enemy 初始化和行为树 BP_Character 组合攻击 首先我们获取攻击动画&#xff0c;在这里使用的是 Easy Combo Buffering 的攻击…

聊聊JSON

引言 JSON的概念 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它基于JavaScript的一个子集&#xff0c;但独立于语言&#xff0c;这意味着它可以被许多编程语言轻松解析。JSON的简洁性和易读性使其成为Web开发中数据交换的…

掌握 NumPy:高效数组处理综合指南(第 2/2 部分)

照片由 兹比内克布里瓦尔 on Unsplash 一、介绍 欢迎来到我关于 NumPy 的教程的第二部分&#xff01;之前&#xff0c;我们已经介绍了以下列表中的前 7 章。现在在这篇文章中&#xff0c;我们将从第 8 章一直到第 14 章。 Numpy 安装数组初始化Numpy 数组限制计算速度和内存使用…

量子计算:1 从薛定谔的猫开始

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则…

基于PHP的民宿管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的民宿管理系统 一 介绍 此民宿管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery.js和echarts.js。系统角色分为用户和管理员。用户可以在线浏览和预订民宿&#xff0c;管理员登录后台进行相关管理等。(在系统…

【python】OpenCV——Color Correction

文章目录 cv2.aruco 介绍imutils.perspective.four_point_transform 介绍skimage.exposure.match_histograms 介绍牛刀小试遇到的问题 参考学习来自 OpenCV基础&#xff08;18&#xff09;使用 OpenCV 和 Python 进行自动色彩校正 cv2.aruco 介绍 一、cv2.aruco模块概述 cv2.…

JAVA小知识28:FIle类文件对象

Java 中的 File 类是 java.io 包中的一个类&#xff0c;用于表示文件和目录路径名的抽象表示。它提供了一些方法来操作文件和目录 一、File的创建 1.1、绝对路径 绝对路径是指从文件系统的根目录开始定位文件或目录的完整路径。它通常以根目录符号开始&#xff0c;在 Window…

【Mac】DMG Canvas for mac(DMG镜像制作工具)软件介绍

软件介绍 DMG Canvas 是一款专门用于创建 macOS 磁盘映像文件&#xff08;DMG&#xff09;的软件。它的主要功能是让用户可以轻松地设计、定制和生成 macOS 上的安装器和磁盘映像文件&#xff0c;以下是它的一些主要特点和功能。 主要特点和功能 1. 用户界面设计 DMG Canva…

Rocky Linux 更换CN镜像地址

官方镜像列表&#xff0c;下拉查找 官方镜像列表&#xff1a;https://mirrors.rockylinux.org/mirrormanager/mirrorsCN 开头的站点。 一键更改镜像地址脚本 以下是更改从默认更改到阿里云地址 cat <<EOF>>/RackyLinux_Update_repo.sh #!/bin/bash # -*- codin…

自研地面站!自主开源无人飞行系统 Prometheus V2 版重大升级详解

自主开源无人飞行系统 Prometheus V2 相对于 Prometheus V1 在多方面做了重大的升级&#xff0c;今天我们将聊聊 Prometheus V2 的地面站升级。 地面站的重大提升 熟悉 Prometheus 的小伙伴们可能知道&#xff0c;V1 版本是没有专门的地面站的。而在 Prometheus V2 中&#x…

VERYCLOUD睿鸿股份亮相亚马逊云科技中国峰会2024

5月30日&#xff0c;为期两天的亚马逊云科技中国峰会在上海世博中心圆满落幕。 多位大咖现场分享&#xff0c;生成式AI时代的数据战略&#xff0c;企业级AI应用&#xff0c;最新技术、产品重磅发布&#xff0c;创新行业解决方案 …… 作为亚马逊云科技的生态合作伙伴&#x…

好大夫在线医生数据医生姓名科室荣誉等202406

好大夫在线医生数据医生姓名科室荣誉等 2024年6月数据&#xff0c;总共934027条数据&#xff0c;可导出为excel,csv等 好大夫在线2024-06月数据 包含简介信息&#xff01; 可见样例数据 样例数据_医生2.xlsx https://www.alipan.com/s/DBEW9MgHEPP 点击链接保存&#xff0…

易宝OA downloadfile 任意文件读取

【产品&&漏洞简述】 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台&#xff0c;具有信息管理、 流程管理 、知识管理&#xff08;档案和业务管理&#xff09;、协同办公等多种功能 易宝OA downloadfile 文件读取&#xff0c;攻击者可通过…

【单片机毕业设计选题24019】-基于STM32的安防监测灭火系统

系统功能: 1. 水泵喷水灭火功能&#xff1a;当火焰传感器监测到火焰时&#xff0c;蜂鸣器报警&#xff0c;水泵工作实现灭火。 2. 风扇功能&#xff1a;当烟雾传感器检测到CO或温度传感器检测到温度超过阈值时&#xff0c;蜂鸣器报警&#xff0c; 启动风扇进行驱散烟雾或降温…

毫秒级响应!清科优能应用 TDengine 建设虚拟电厂运营管理平台

小T导读&#xff1a;在清科优能的虚拟电厂运营管理平台建设中&#xff0c;项目初期预计涉及约一万台设备、总数据采集量达数十万&#xff0c;在数据库选择上&#xff0c;其希望能支持至少两千台设备的并发数据处理。本文介绍了清科优能的数据库选型经验以及最终应用效果&#x…

简易人工智能入门

一、监督or非监督 监督学习&#xff08;Supervised Learning&#xff09;&#xff1a;训练集有标记信息&#xff08;Y&#xff09;&#xff0c;学习方式有分类和回归 无监督学习&#xff08;Unsupervised Learning&#xff09;&#xff1a;训练集没有标记信息&#xff0c;学习…

后端实现预览pdf,mp4,图片

PDF预览 /*** pdf预览* param response*/RequestMapping(value "/preview")public void showPdf(HttpServletResponse response) {try {//String filePath this.getClass().getClassLoader().getResource("../../static/pdf/readme.pdf").getPath();Stri…

解决virtualbox虚拟机与主机之间复制粘贴

1、在VirtualBox管理器中设置共享粘贴板和拖放方向为双向 2、在存储中设置使用主机输入输出&#xff08;I/O&#xff09;缓存。 3、在存储→控制器&#xff1a;SATA→***.vdi下勾选固态驱动器 4、在虚拟机→设备→安装增强功能 如果上述操作重启虚拟机后&#xff0c;还不行&am…