C++ 入门

001 c++ 如何工作

  • 任何以 # 开头的语句,都是预处理语句,所谓的预处理语句,在编译之前,就已经被处理了

  • 关键字 include:找到 <> 文件(通常称为“头文件”),然后将 <> 中的所有内容拷贝到现在的文件里

  • main()比较特殊,虽然它的返回值类型是 int,但它不一定需要返回值,如果不设置返回值,默认返回 0

  • << 运算符叫做重载运算符,可以看成是一个函数(重载运算符 == 函数

  • 解决方案平台(Solution Platforms):编译代码的目标平台;
    x86:目标平台是 windows32 位(生成 32 位的 windows 应用程序)

  • 预处理后,我们的文件将被编译,编译器将所有 c++ 代码 -> 二进制的机器码

  • 源文件.cpp --编译--> 目标文件.obj --链接--> 可执行文件.exe

  • 链接:将 .obj 文件链接(合并)到一起,编成一个可执行文件。比如函数声明,是不同.cpp之间的合并。这里强调一下,只有函数调用的时候,才会产生链接,声明的时候,是不会进行链接的。声明只是在函数被调用的时候,能够找到合适的链接函数

  • 头文件不会被编译,头文件拷贝过来时,已经被编译过了;
    编译一个单独的文件时,不会 link。单个文件编译快捷键:ctrl + F7

Main.cpp

#include <iostream>  # 这一条语句其实包含了 50623 行代码,所以 Main.cpp 文件才会很大

void Log(const char* message);

int main()
{
	// std::cout << "Hello World!" << std::endl;  // 将字符串 Hello World! 推送到 cout 流中,然后打印到终端;endl 告诉终端,跳到下一行
        Log("Hello World!!");
	std::cin.get();  // 程序暂停执行,直到按下 enter 键
}

Log.cpp

#include <iostream>

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




002 c++ 编译器如何工作

  • 编译器本质工作:将我们的文本文件 -> 目标文件,便于后续的链接

  • 我们先按照编程语言的规则,将代码进行记号化和解析成编译能理解和推理的格式,然后编译器对所有的代码进行预处理,这儿会产生抽象语法树。编译器的工作就是将我们的代码转换成常量数据或指令,一旦编译器生成这个 AST ,它可以生成实际的机器码

  • 抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构,这所以说是抽象的,是因为抽象语法树并不会表示出真实语法出现的每一个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现

  • 编译器只会编译 .cpp 的 c++ 文件,这些 cpp 文件被称为翻译单元(一个 CPP 文件不一定等于一个翻译单元,如果项目较小,那么每个 CPP 文件都是一个翻译单元)

  • 实际上,没有所谓的文件,编译器根本不 care 文件不文件,文件只是提供给编译器源代码的一种方式而已

  • 下面的例子,主要想说明的就是,编译器在处理头文件时,会把头文件中的所有内容都复制到当前文件

  • 强调一下,我们平时在写代码的时候,要尽可能的简洁,尽可能的优化我们的代码,比如将 Math.cpp 中的 int result = a * b; 一行去掉,直接 return a * b; 编译在工作时,会节省四行代码

Math.cpp

int Math(int a, int b)
{
	int result = a * b;
	return result;
#include "EndBrace.h"

EndBrace.h

}




003 c++ 链接器如何工作

  • 链接的主要工作:找到每个符合和函数在哪,并把他们链接起来

  • 源文件被编译之后,每个文件都是单独的翻译单元,他们之间没有任何关系,不能交互

  • 下面的例子很好的说明了链接的作用,Multiply() 定义了,即使你在当前的翻译单元里没有调用 Multiply(),但是链接器会认为你在其他的文件里会用到这个函数,所以,它还是会被进行链接。函数内部的函数调用,也会进行链接,所以调用的 Log() 和 Log.cpp 文件中的 Logr() 不对应,就会产生链接错误

  • 我们可以使用 static 函数,直接规定死,Multiply() 只在当前文件下使用,不让它和其他变量或函数进行链接,就会避免上述错误

Math.cpp

# include <iostream>

void Log(const char* message);

// static int Multiply(int a, int b)
int Multiply(int a, int b)
{
	Log("Multiply");
	return a * b;
}

int main()
{
	std::cin.get();
}

Log.cpp

#include <iostream>

void Logr(const char* message)
{
	std::cout << message << std::endl;
}
  • 下面介绍一下,函数定义重复,导致的链接错误

  • 这里其实会报错的,Math.cpp 和 Log.cpp 都包含了头文件 # include "Log.h",也就是说,Log() 的定义被复制了两遍,产生重复链接错误。如果我们将 Log() 的修饰符改为 static 或 inline ,则会消除链接错误

  • 还有一种解决办法就是,在 Log.h 中只声明 Log(),然后在 Log.cpp 中定义 Log(),这样也不会产生链接错误

Log.h

# include <iostream>

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

Log.cpp

# include "Log.h"

void InitLog()
{
	Log("Initialized Log");
}

Math.cpp

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

static int Multiply(int a, int b)
{
	Log("Multiply");
	return a * b;
}

int main()
{
	std::cout << Multiply(5, 8) << std::endl;
	std::cin.get();
}
  • inline 的作用就是获取实际的函数体,并将函数调用替换为函数体,比如在 Log.cpp
# include "Log.h"

void InitLog()
{
	// Log("Initialized Log");
        std::cout << "Initialized Log" << std::endl;
}




004 变量和函数

  • 当我们创建一个变量的时候,他们会被放到内存(堆和栈)

  • 不同变量类型之间的唯一区别:在内存中所占大小,而不同类型的变量所占内存大小与编译器有关

  • int 数据类型可以存储 -20亿 ~ +20 亿之间(约数)的值

  • 变量的类型大小与它能存储多大的数字直接相关

  • unsigned 数据类型取值范围 0 ~ 40 亿,是因为它把符号位移除了

# include <iostream>

int main()
{
        float variable = 4.4f;  // 在值的后面添加 f 区分 float 和 double 
        double var = 9.9;
	std::cout << variable << std::endl;
	std::cout << var << std::endl;
	std::cin.get();
}
  • bool 数据类型的取值为 true 或 false,其在计算机中表示为 1 或 0,但是该类型的变量在内存中,占 1Byte ,虽然其只是 0 或 1,只用 1bit 就行,但是在处理寻址内存时,不能寻址只有 1bit 位的内容,只能寻址字节

  • 可以使用 sizeof() 查看变量所占内存

Main.cpp

# include <iostream>

int main()
{
        bool var = false;
	std::cout << sizeof(var) << std::endl;  // 1
	std::cin.get();
}
  • 函数,不是 c++ 类里的

  • main() 是一个特殊的函数,可以不写函数函数返回值,但是其他的所有函数,都需要写返回值,否则会报错

  • 函数声明通常存储在头文件中,在翻译单元或 cpp 文件实现定义





004 c++ 头文件

  • 对于 c++ 而言,头文件通常用于声明某些类型的函数

  • 函数完美地解决了重复代码的问题,而头文件完美解决了函数调用必须有声明的问题,有了头文件,就不用在每个翻译单元声明函数了

  • 如果我们在 .h 头文件里包含了 #include 那么在翻译单元里,只要包含了 .h 文件,不添加 #include 也可以

  • pragma 是一个被发送到编译器或预处理器的预处理指令

  • pragma once 监督头文件,阻止单个头文件多次被包含

Log.h

# pragma once  // 只包括这个头文件一次
  • 如果我们要包含的文件,在其中的一个文件夹里,用尖括号 <> 告诉编译器,搜索包含路径文件夹。说白了就是,用引号可以指定相对路径

  • 而引号 "" 通常是告诉编译器,包含相对于当前文件的文件

  • c++ 标准库,通常没有后缀 .h,是为了和 c 进行区分

  • 在 vs 里,可以右键打开文档,查看所选头文件完整内容;右键函数名,可以查看函数定义

持续更新ing....

原文链接:https://www.cnblogs.com/Kiiiim4499/p/17379443.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++ 入门 - Python技术站

(0)
上一篇 2023年5月11日
下一篇 2023年4月17日

相关文章

  • 【Visual Leak Detector】配置项 StartDisabled

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 StartDisabled 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置是否禁用自动初始化 2.1 测试代码 2.2 StartDisabled = no 时的输出 2.3 StartDisabled …

    C++ 2023年4月18日
    00
  • 信奥赛题1105:数组逆序重存放

    新奥赛一本通,题11051105:数组逆序重存放 时间限制: 1000 ms         内存限制: 65536 KB提交数: 70600                通过数: 47540【题目描述】将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。【输入】两行:第一行数组中元素的个数n(1<n&l…

    C++ 2023年5月5日
    00
  • 洛谷:P5716日份天数

    题目描述 输入年份和月份,输出这一年的这一月有多少天。需要考虑闰年。 输入格式 输入两个正整数,分别表示年份 \(y\) 和月数 \(m\),以空格隔开。 输出格式 输出一行一个正整数,表示这个月有多少天。 样例 #1 样例输入 #1 1926 8 样例输出 #1 31 样例输入 #2 2000 2 样例输出 #2 29 提示 数据保证 \(1583 \le…

    C++ 2023年4月24日
    00
  • C++重载的奥义之运算符重载

    0、引言         重载,顾名思义从字面上理解就是重复装载,打一个不恰当的比方,你可以用一个篮子装蔬菜,也可以装水果或者其它,使用的是同一个篮子,但是可以用篮子重复装载的东西不一样。         正如在之前的文章《重载的奥义之函数重载》中介绍的类似,函数的重载是指利用相同的函数名设计一系列功能相近,但是功能细节不一样的函数接口;因此运算符重载也是指…

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】配置项 StackWalkMethod

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 StackWalkMethod 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置调用堆栈的跟踪方法 2.1 测试代码 2.2 StackWalkMethod = fast 时的输出 2.3 StackWal…

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】核心源码剖析(VLD 2.5.1)

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇对 VLD 2.5.1 源码做内存泄漏检测的思路进行剖析。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 源码获取 2. 源码文件概览 3. 源码剖析 3.1 通过 inline hook 修补 LdrpCallInitRoutine 3.2 通过 IAT hook 替换内存操…

    C++ 2023年5月11日
    00
  • 08、【算例】openfoam溃坝

    7.1 溃坝 官网目录:$FOAM_TUTORIALS/multiphase/interFoam/laminar/damBreak 7.1.1 介绍 本案例使用interFoam两相算法,基于流体体积分数(VOF)法,每个网格中的相体积分数(alpha)通过求解一个组分运输方程确定。物理属性基于这个相分数通过加权平均计算。 7.1.2 网格生成 blockM…

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】配置项 ReportTo

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 ReportTo 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置报告输出的位置 2.1 测试代码 2.2 ReportTo = debugger 时的输出 2.3 ReportTo = file 时的输出…

    C++ 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部