SecureCoding in C and C++(二)

news2024/9/21 0:40:06

经过上期的环境搭建过后,我们将正式的学习C++系列,首先要学习的是C++的一些常用的变量
从编译和连接学起似乎也是不错的选择。
个人总结的一句话:编译其实就是对预处理语句进行处理后,然后对语句进行处理。对预处理语句,例如:#include 之类的处理方式其实就是将文件内容复制到对应的cpp文件内,随后生成obj文件,然后再经过链接(也就是link)将其处理。
好的让我们开始学习变量:

1. 变量

说起变量,学习过其他编程语言的小伙伴们其实很清楚,大致上也就那些,什么int char string float这些基本都是常见的了,但是这里我想说的是,其实他们去做什么作用我并不关心,就像一个人的身高和体重,利用整数和浮点数来表示我不是很关心,我关心的只是不同变量的大小之分。
来举个例子:

#include<iostream>
int main()
{
    int v =8;
    std::cout<<"hello world !\n" <<std::endl;
    std::cout<<v<<std::endl;
}

这里我们明显的使用了整型,也就是int

1.1整型变量 int

整型变量的作用是在一定范围内存放整数
占的大小是4个字节,是一个有符号变量,其空间大小为-20亿到+20亿
4Byte =32bit 其中的一位占做符号位,也就是实际上来说的31位表示数据位。
那么我们也可以让其始终为正,来表示全32位都是有效的数据的变量,这就引来了无符号整型:
unsigned int
这样看来,其32位全部可以用0或1来表示,因此他的大小为20亿的两倍,大概为42亿。

1.2 字符变量char

char 占1位
其实,我起初所说的对变量真正期望你使用其来表示什么数字其实并不关心,原因就在char里
其实char是用来表示一个字符的,但是你也可以用其来表示数字。
举个例子:

#include<iostream>
int main()
{
    char a ='A';
    char b =65;
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    
}

在我们进行build之后,运行结果为:
在这里插入图片描述
那么为什么呢? 为什么char b输入的是数字,但是实际上出现的是A呢?这其实就是Ascll
说白了其实就是一些约定,所以在C++使用的过程中,我们没必要去让自己遵循一些既定俗成的约定,没啥必要,我们要发挥自己的主观能动性!
变量与变量之间唯一的区别,个人认为是在变量被创建的时候分配了多少空间
剩余的变量就不一一介绍了
short2字节
long 4 字节
long long 8字节

1.3 float double

float为4字节
double为8字节
float变量在定义的时候要在其后面加入f

    float c=5.5f;
    double d=5.2;

1.4 Bool

bool,学过js肯定都知道吧,其实就是boolean 用来返回true或者false
在这里插入图片描述
但是当我们使用cout去打印bool变量的时候
会出现的是:
在这里插入图片描述
是因为计算机并不知道什么是真的,什么是假的,他只知道0是0
因此bool里除了0表示假的,其余都是真的。
但是bool也跟char一样是占一个字节的。
有人可能就问了:
为什么不是一个bit呢?既然只表示0或者1,1位不就够了吗?
确实是这样的。1位确实就够了,但是当我们的CPU去寻找这个bool值的时候,如果这个bool为1位的话,我们没有把那去寻址只有1一个bit位的内容,ds和【】都需要2个字节。所以我们寻址的时候必须得按字节来寻址,经过cs的左移之类的。
因此我们不能去创建只有1bit的bool,我们要寻址。但是我们可以在一个bool内创建8个bool值,1bit1个。这都是后话了

我们也可以用sizeof去查看对应的变量类型占了多少个字节。
如下:
在这里插入图片描述
运行结果如下:
在这里插入图片描述
int占4字节、double 8字节、float4字节、char1字节 long 8字节 long long 8字节 short2 字节

1.5 总结

常用的变量也就是以上的内容了,剩余其他变量可以用他们进行组合,当然我们也可以让其变成指针型的变量或者引用。这都是后话了。

2.函数

什么是函数?其实就是一个被我们设计去实现某种功能的代码块罢了。也解决了实现某个功能,我们不必的去重复写的麻烦。函数有几个值得注意的地方:

  1. 函数的返回值
  2. 函数所要传入的参数
    例子:
int Multiply(int a,int b)
{
    return a*b;
}

这个函数的作用是返回两个整数的乘积,所以其返回结果是 int 也就是 写在了函数一开始的地方,随后传入了两个整型int变量。
那么如何去调用这个函数呢?
我们在main函数中定义两个整型的变量即可:
在这里插入图片描述
函数其实还是比较简单的哈(

3. 头文件

头文件说白了就是一个用来声明函数的文件。
举例:
为了输出服务器的日志方便,我们需要一个Log函数去打印服务器的日志到终端里:
这里我们编写一个十分简单的函数Log,

void Log(const char * message)
{
    std::cout<<message<<std::endl;
}
void InitLog()
{
    Log("Initializing Log");
}

我们将log放置在一个叫Log.h的头文件内;
在我们的main函数所在的文件内未进行#include “Log.h”的文件声明之前,我们是无法在main函数中使用的

#include<iostream>
int Multiply(int a,int b)
{
    return a*b;
}
void MultiplyAndLog(int a, int b)
{
    std::cout<<Multiply(a, b)<<std::endl;
}


int main()
{
    int a=1;
    int b=2;
    std::cout<<Multiply(a, b)<<std::endl;
    MultiplyAndLog(2, 3);
    Log("hello");
    InitLog();
}

我们将main函数所在文件main.c中尝试使用Log.h中有的函数,并且在Xcode中进行编译:
在这里插入图片描述
会报错:无法匹配到Log的函数调用和不清楚的InitLog定义。
这是因为我们没有对其进行声明;也就是没有调用Log.h的缘故
在我们加入之后,程序正常运行了。
当然,我们也可以这样:
在一个其他的文件内,编写log函数:
在这里插入图片描述
这里我们在一个单独的cpp文件中编写了log和InitLog函数,我们可以在main函数所在的cpp里进行声明:
在这里插入图片描述
可以看到成功运行了:
在这里插入图片描述
这里进行声明的时候,只需要将对应函数的 返回值,名称,传入参数输入即可
如这里的:

void Log(const char * message);

当然我们也可以在头文件中进行声明,随后在main.cpp中调用头函数
在这里插入图片描述
这样也是可以的。
但是有个问题需要深思:

3.1 头文件中 #pragma once的运用

我们知道cpp文件在进行编译的时候,其本质就是将预处理,也就是带“#”后面的内容进行复制粘贴行为,因此假设我们在处理一个含有结构体的头文件的时候,我们一不小心在main函数所在的cpp文件内进行了两次重复的调用,那么我们就生成了两个一模一样的结构体:
例如:
在这里插入图片描述
然后我们在main中引用了两次Log.h
在这里插入图片描述
这个时候就会报错。
错误为:
Redefinition of 'People'
这是因为预处理的特征是复制粘贴,导致了两个相同的结构体出现了。
那么我们需要在头文件中加入#pragma once 进行处理,这个预处理语句的作用就是防止头文件的内容被重复的调用,导致出现 Redefinition 的错误。

3.2 ifndef的运用

除了3.1中所提到的#pragma once
我们还可以利用预处理的特性来解决这个问题:
即在头文件中加入:
#ifndef _LOG_H
#define _LOG_H
#enif
来进行判断,其原理是:在编译器进行预处理的操作时,首先要将预处理的文件复制,然后粘贴到调用中:
这里进行复制时,会出现以下情况:
ifndef _LOG_H
define _LOG_H
你的代码:
endif
会首先执行:ifndef判断 判断是否定义了_LOG_H
如果没有定义,则进行定义 随后执行你的函数
如果定义了,那么直接进行endif。
来尝试下,例子如下:
在这里插入图片描述
这种情况下,即使在main中调用了两次的Log.h也不会出现错误:
在这里插入图片描述
还有一点需要注意的是 #include “”引号表示的是 相对于当前文件的情况,属于相对路径
而#include<>使用的是绝对路径
文件头也很简单呀~

4. 使用IDE来调试

4.1 使用VisualStudio

  1. 设置断点:
    直接按F9就可以设置断点
    在这里插入图片描述
    再点击一次红点就可以取消断点
    随后确保在debug模式下 点击第二个红色箭头所指的地方进行debug调试

在这里插入图片描述
点击后,界面会发生变化
在这里插入图片描述
这里有三个调试步骤

  • 逐语句 (step in) 进入当前函数,这里是进入Log函数 然后从Log函数里进行其他的调试 快捷键 F11
    在这里插入图片描述
  • 逐过程(step over) 跳过当前函数执行下一行,即不进入Log函数,直接调试下一行 快捷键F10
    在这里插入图片描述
  • 跳出(step out) 跳出当前函数回到断点处,退出调试模式. 快捷键shift + f10
    在这里插入图片描述
  1. 读内存
    我们按照第一部分的debug 进行
    当我们按F11 进入到 Log函数中
    在这里插入图片描述
    可以看到 message的内容为"Hello world !"
    好像有些许简单了,让我们来加入一些其他的变量来增大难度:
#include<iostream>
#include "Log.h"
int main()
{	
	int a = 8;
	const char* string = "Hello";
	for (int i = 0; i < 5; i++)
	{
		const char c = string[i];
		std::cout << c << std::endl;
	}
  	Log("Hello World!");
	std::cin.get();

}

新的代码后,我们不加断点直接进行运行来查看一下结果:
在这里插入图片描述

然后我们把断点设在int a处;
在这里插入图片描述
在未步入之前 a是多少呢?
在这里插入图片描述
为什么? 我设定的a明明是12403 啊
因为我们还没有进行执行 int a的指令,换句话说 这里只是cpu通过 cs:ip 读取到了这句 类似于 mov ax,8
但是还没有进行执行,ip还没有+3 的情况下.因此这里的值是未初始化的 a的值.所以是正常的.
一直步入到第6行的时候,再进行步入的时候才发现右下角中的string出现了值
在这里插入图片描述
这里要介绍下调试的窗口:

  • 自动窗口
    在这里插入图片描述

这里面可以看到IDE自动给你生成的名称以及其对应的值和类型

  • 局部变量
    在这里插入图片描述
    这里看到的是程序运行过程中所用到的局部变量的值
  • 监视1
    在这里插入图片描述

可以通过箭头所指方向进行添加所要监视的变量.

  • 内存读取
    在这里插入图片描述
    使用后可以查看内存指定位置的值
    在这里插入图片描述
    这里查看了Hello world
    也可以使用 &变量名来查看变量
    &a来试一下
    在这里插入图片描述
    这里可以看到就是a的值 08
    如果看到的是CC
    那么说明这段部分还没有被创造栈,也就是这个变量没有被初始化.

4.2 使用Xcode

这里我们使用Xcode来进行调试,首先把程序补全:

	#include<iostream>
#include "Log.h"

int main()
{   int a = 8;
    a++;
    const char * string ="Hello";
    for (int i =0 ;i <5 ;i++)
    {
        std::cout<<string[i]<<std::endl;
    }
    Log("Hello world!");
    std::cin.get();
}

然后我们来看下Xcode的debug功能:
在这里插入图片描述

  • step in 也就是 F7 步入 就是进入函数内部进行debug
  • step over F6跳过此函数 执行下一行
  • step out F8 跳出
  • create breakpoint currently 是comman +\ 是精确的创建断点
    相较于Vs来说 Xcode的debug模式是全一些的 甚至可以通过 comman + Y来激活/不激活某处断点。
    这里还是老样子在 int a处设下断点
    在这里插入图片描述
    这就是Xcode的调试界面了,与Vs不同的是,得手动点击播放按钮后才可以开始调试。
    我们分两个区域来查看
    第一个区域是左侧栏
    在这里插入图片描述
    这里显示的元素有 程序运行进程的pid 占用内存 以及 程序运行的线程 和当前调试的程序名:main
    点击main的下面会出现当前程序运行的情况
    在这里插入图片描述
    由于博主的MacBook是M系列的,因此跟Intel的指令读起来还是有些许不同的,不会存在常用的ax,bx等通用寄存器。这里就不必多言,关注的是debug的过程和思想。
    让我们来看另一个区域,就是debug区域的下方:
    在这里插入图片描述
    这个窗口跟VS的类似,有auto 、local 和all
    auto就是自动 local是本地的变量 all是都显示出来
    与VS不同的是 这里的监视器写在了左边
    在这里插入图片描述
    对于查看内存来说,我们只需右键想看到的变量的名称来进行查看内存
    这里查看的是string

在这里插入图片描述
结果如图:
在这里插入图片描述
可以看到,内容就展现在了右边。

看起来还是Xcode的debug展现的功能比较全一些,这也为我后期对VS的优化做了铺垫。

5. 常见的语法

5.1 if else语句

先来看一下简单的if else的示例
在这里插入图片描述
这里将Compar之后的结果 存储在bool变量里,可以直接方便的去套用if语句
我们更应该关心这个if 语句在实际的运行过程当中发生了什么
让我们来运行一下:
在这里插入图片描述
当然,显示了hello world !
当我们把 x 改为6
什么也没发生。这是当然啦
让我们在 int x的地方下断点
在这里插入图片描述
当我们一步一步的去步入的时候,ComparisonResult为false;
因此就退出了。
让我们去VS里面看一下汇编是怎么写的(别问为什么不用Xcode看,问就是没学过arm的)
在这里插入图片描述
首先使用mov 将 6放入 寄存器里
随后开始判断ComparisonResult的值
在这里插入图片描述
也是将其放入寄存器里,随后使用jne比较(jump not equal) 这里看出 x并不是为5 实际上是6 则跳转到了 07FF742BE6825h那边
最后因为不相等,就跳转到了 cin.get()
在这里插入图片描述
再来看一下if语句对应的汇编吧
在这里插入图片描述
这里的语句实际上是,将ComparisonResult的内容进行比较,然后执行je(jump equal) 相等就跳转 实际上比较的是是否与false相等:
这里因为不是false,所以就不跳转,转身去执行下面的log函数
在这里插入图片描述
实际上我们可以进一步的简化代码,使其更加清晰。
在这里可以这样进行简化
在这里插入图片描述
众所周知,只要是bool不为0
那么都为真,这里直接写成x就很合理了。
对于指针我们也是可以这样写的。
例如:
在这里插入图片描述
这样对于指针来说,只要不是空指针或者0,就可以成功的调用Log()

在这里插入图片描述
可以看到已经成功打印了。
那么如果我们将其设为nullptr,则不会打印。
在这里插入图片描述

在这里插入图片描述
就是这样!
好了由于时间的关系,这篇文章最终以一万字结束。期待下一篇,下一篇中,我将继续带来关于C++相关的精华部分,指针、引用、类与结构体等待。
喜欢的话点个关注,求个赞赞和收藏~~

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

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

相关文章

C++——list列表容器经典案例——手机按销量降序排列,若销量相同则按价格降序排列

需求&#xff1a;使用list列表对商品进行排序&#xff0c;先通过销量降序排&#xff0c;若销量相同则根据价格升序排列输出 涉及到的知识点&#xff1a;list列表容器、自定义数据类型、自定义排序规则 实现步骤&#xff1a; 1&#xff0c;自定义数据类型Product&#xff0c;…

Android 实现多进程通讯(如何实现多进程开发,Binder、AIDL)

目录 1&#xff09;为什么App需要多进程 2&#xff09;什么是多进程开发? 3&#xff09;如何实现多进程开发&#xff1f; 4&#xff09;跨进程间通讯(案例) 5&#xff09;多进程需要注意什么问题&#xff1f; 6&#xff09;多进程的底层原理是什么&#xff1f;【待写】 …

【Python机器学习】树回归——使用Python的tkinter库创建GUI

机器学习给我们提供了一些强大的工具&#xff0c;能从未知数据中抽取出有用的信息。因此&#xff0c;能否这些信息以易于人们理解的方式呈现十分重要。如果人们可以直接与算法和数据交互&#xff0c;将可以比较轻松的进行解释。其中一个能够同时支持数据呈现和用户交互的方式就…

手机IP地址:是根据网络还是设备决定的?

在日益数字化的今天&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。它不仅是我们沟通的桥梁&#xff0c;更是我们获取信息、享受娱乐和完成工作的得力助手。然而&#xff0c;在使用手机上网的过程中&#xff0c;你是否曾经好奇过手机的IP地址是如何被分配的&#xf…

Java中class文件结构分析二

第17个常量池:01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01&#xff1a;tag位表示的是utf8类型的字面量常量 00 15 二个字节表示的是字面量常量的长度为21 接下来21个字节: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56…

经典大语言模型解读(1):BERT——基于双向Transformer的预训练语言模型

论文&#xff1a;BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 前言 BERT&#xff08;Bidirectional Encoder Representation from Transformer&#xff09;是Google于2019年提出的预训练语言模型。与寻常的Transformer架构不同&#…

eval和长度限制

目录 源码 解决方案 方法一 方法二 方法三 源码 <?php $param $_REQUEST[param]; if(strlen($param)<17 && stripos($param,eval) false && stripos($param,assert) false) {eval($param); } ?> 限制条件&#xff1a; 传入的参数长度不能…

Go语言+Vue3开发前后端后台管理系统实战 用户管理的前端界面和表结构分析

首页&#xff1a; 用户管理界面&#xff1a; 到这一步以后来看一下后端代码的表结构是如何设计的&#xff1a; 后端代码中&#xff0c;使用的操作MySQL的技术是gorm&#xff1a; gorm.io/gorm v1.25.5其中&#xff0c;用户表的定义位置如下&#xff1a; 此时的完整代码如…

C++虚函数习题

#include <iostream>using namespace std;class Animal { public:Animal() {}virtual void perform()0; };class Lion:public Animal { public:Lion() {}void perform(){cout << "狮子会吃小朋友&#xff01;&#xff01;&#xff01;快跑&#xff01;&#x…

设计模式(1)创建型模式和结构型模式

1、目标 本文的主要目标是学习创建型模式和结构型模式&#xff0c;并分别代码实现每种设计模式 2、创建型模式 2.1 单例模式&#xff08;singleton&#xff09; 单例模式是创建一个对象保证只有这个类的唯一实例&#xff0c;单例模式分为饿汉式和懒汉式&#xff0c;饿汉式是…

IP问题总结

IP基础知识 IP 在 TCP/IP 参考模型中处于第三层&#xff0c;也就是⽹络层。 ⽹络层的主要作⽤是&#xff1a;实现主机与主机之间的通信&#xff0c;也叫点对点&#xff08;end to end&#xff09;通信。 1.⽹络层与数据链路层有什么关系呢&#xff1f; 其实很容易区分&#…

eNSP 华为浮动路由

R1&#xff1a; <Huawei>system-view [Huawei]sysname R1 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 172.16.1.1 24 [R1-GigabitEthernet0/0/0]int g0/0/1 [R1-GigabitEthernet0/0/1]ip add 10.10.1.1 24 [R1-GigabitEthernet0/0/1]quit [R1]vlan 10 //e口是…

使用docker搭建aria2-pro+ariang并在alist中配置

一、安装aria2-pro 1.创建映射目录 # 配置目录 mkdir -p /usr/local/docker/aria2/config # 下载目录 mkdir -p /share_root/download-aria22.创建容器 docker run -d \--name aria2-pro \--restart unless-stopped \--log-opt max-size1m \--network host \-e PUID$UID \-e …

【秋招笔试】8.12-4399秋招(第一套)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收…

全网最详细HAProxy入门小知识

目录 一. 负载均衡 负载均衡的意义&#xff1a; 负载均衡的类型&#xff1a; 二. HAProxy 简介 HAProxy 的特点&#xff1a; 社区版和企业版&#xff1a; 三. HAProxy 的安装和服务信息 1、实验环境 1&#xff09;安装并配置 Nginx 2&#xff09;在客户端测试 2、安装…

【项目实战】C++视频共享点播系统

目录 一、项目介绍 1.1 对视频共享点播系统的认识 1.2服务端程序负责功能 1.3 服务端功能模块划分 1.4 项目界面演示 1.5预备知识 二.环境搭建 2.1 安装 Jsoncpp 库 2.1.1 使用jsoncpp 2.2 引入httplib库 2.2.1 安装Git&#xff08;如果你的系统尚未安装Git&#xf…

基于Hadoop的共享单车分布式存储与计算

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍研究背景研究目的和意义国内外研究现状总体研究思路数据可视化每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 共享单车的普及带…

Elasticsearch:使用 ES|QL 进行地理空间搜索

作者&#xff1a;来自 Elastic Craig Taverner 多年来&#xff0c;Elasticsearch 一直具有强大的地理空间搜索和分析功能&#xff0c;但其 API 与典型的 GIS 用户习惯的 API 截然不同。在过去的一年中&#xff0c;我们添加了 ES|QL 查询语言&#xff0c;这是一种管道查询语言&a…

React原理之React整体渲染流程

前置知识&#xff1a;深度优先搜索(DFS)、Fiber 节点 在上一篇 React原理篇之 React 整体架构解读中&#xff0c;提到了 Fiber 架构中的几个核心概念&#xff1a; Scheduler&#xff08;调度器&#xff09;&#xff1a;根据任务的优先级安排任务执行顺序。Reconciler&#xff…

CUDA-MODE 第一课课后实战(下)

我的课程笔记&#xff0c;欢迎关注&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode CUDA-MODE 第一课课后实战&#xff08;下&#xff09; Nsight Compute Profile结果分析 继续对Nsight Compute的Profile结果进行分析&#xff0…