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日

相关文章

  • XMake学习笔记(1):Windows(MSYS2)下MinGW-w64环境搭建和XMake安装

    以前写的C++基本都是C with STL,大多是面向过程的算法题,或者比较小的项目,然后经常报各种编译错误(对编译原理不熟),经常把人搞到崩溃,搞不懂构建、链接之类的东西。 现在开始记录一下XMake的学习笔记,记录一些学习过程中踩的坑,在这篇文章,你将学习到Windows下利用MSYS2进行Mingw-w64环境搭建和XMake安装,并用Xmake构建一…

    C++ 2023年4月30日
    00
  • 【Visual Leak Detector】源码编译 VLD 库

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 源码的编译。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. VLD 库的依赖文件 2. 源码编译生成 VLD 库 3. 配置环境变量 4. 使用 VLD 库 1. VLD 库的依赖文件 以 vld2.5.1 版本为例,下载源码 后,源码包中各文件的用途可看本人另一…

    C++ 2023年4月24日
    00
  • C++的对象和类

    一、问题引入 区分面向过程编程和面向对象编程的最大的特性就是 类,类是一种将抽象转换为用户定义类型的C++工具,它将数据表示和操纵数据的方法组合成一个整洁的包。 那么如何声明类、定义类、调用类? 以 C++ Primer Plus:中文版 (第六版) 的股票类举例说明。 二、解决过程 2-1 类抽象 股票类的抽象化 获得股票 增持股票 卖出股票 更新股票价格…

    C++ 2023年4月17日
    00
  • 面试最常问的数组转树,树转数组 c++ web框架paozhu实现

    刚毕业同学,找工作常被问 二维数组转树,树转二维数组 需要支持无限层级实现,如果你了解这个语言那么实现起来还要一番思考 c++ web框架 paozhu使用 需要实现数据库表数据到前台菜单实现,就是这种功能 二维数组转树,树转二维数组 保存时候树二维数组,展示时候树树状。 这个技术难点在于无限递归,这个树程序基本原理 现在看看c++怎么实现的,无限递归,家肯…

    C++ 2023年4月25日
    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
  • 【Visual Leak Detector】配置项 ReportFile

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

    C++ 2023年4月18日
    00
  • 最少步数

    在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一…

    C++ 2023年4月25日
    00
  • <五>move移动语义和forward类型转发

    move : 移动语义,得到右值类型forward:类型转发,能够识别左值和右值类型 只有两种形式的引用,左值引用和右值引用,万能引用不是一种引用类型,它存在于模板的引用折叠情况,但是能够接受左值和右值区分左值和右值得一个简单方式就是能不能取地址一个右值一旦有名字那么就变成了左值 #include <iostream> using namespa…

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