What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:cpp:courses:cpp_basic_deep:chpt_0 [2024/01/23 15:40] – [对象生命周期的精确控制] codingharecs:programming:cpp:courses:cpp_basic_deep:chpt_0 [2024/04/14 11:45] (当前版本) – [编译链接模型] codinghare
行 28: 行 28:
   * 一系列不断衍进的标准集合   * 一系列不断衍进的标准集合
     * C++98/03 , C++11 , C++14 , C++17 , C++20 , C++23 ?     * C++98/03 , C++11 , C++14 , C++17 , C++20 , C++23 ?
 +  * 三种编程范式:面向过程、面向对象、泛型
 +  * 函数重载、异常处理、引用
   * 语言本身的改进   * 语言本身的改进
-    * Memory Model +    * Memory Model(多线程角度 C++ 11) 
-    * Lambda Expression+    * Lambda Expression(C++11)
   * 标准库的改进   * 标准库的改进
-    * type_traits / ranges +    * type_traits / ranges(容器扩展) 
-    * auto_ptr+    * auto_ptr(C++11 中被智能指针替代) 
 +==C++ 标准的工业界实现== 
 +  * MSVC / GCC / Clang 
 +    * 每个编译器可能并不完全遵照标准 
 +      * https://godbolt.org/z/cKMjK3 
 +    * 不同的实现存在差异 
 +      * https://godbolt.org/z/6hnPhY 
 +==不能脱离具体的语境讨论 C++== 
 +  * 我使用什么样的标准 
 +  * 我使用什么样的工具 
 +==编写程序时要注重== 
 +  * 性能 
 +  * 标准:尽量使用跨平台的库(符合标准的库),避免移植问题 
 +====C++ 的开发环境与相关工具==== 
 +  * 编译器:Visual C++ / GCC (G++) / Clang (Clang++) 
 +===工具=== 
 +  * time: 使用 linux 自带的 time 测试程序运行时间 
 +<code bash> 
 +/usr/bin/time  
 +</code> 
 +  * valgrind:查内存泄漏 
 +  * Cpp reference 
 +  * Compiler explorer  
 +    * 可以查看程序对应的汇编代码 
 +    * 代码的分颜色:对应汇编和C++源码 
 +    * 可选不同编译器,方便做比较 
 +  * C++ Insights:解释代码(比如 for range 是怎么实现的) 
 +  * youtube 
 +    * cppcon 
 +====C++ 的编译 / 链接模型==== 
 +通常情况下,处理程序的方式有两种: 
 +  - 简单加工 
 +  - 编译+链接 
 +==简单加工模型== 
 +将所有的内容都堆在一块,直接进行编译: 
 +{{ :cs:programming:cpp:courses:cpp_basic_deep:cpp_ref_0_complie.jpg?400 |}} 
 +  * 加工时间长 
 +  * 少量修改也会导致全部重新加工 
 +==分块处理== 
 +{{ :cs:programming:cpp:courses:cpp_basic_deep:cpp_ref_0_complie_2.jpg?400 |}} \\ \\  
 +每个文件单独编译,再进行链接 
 +  * 编译耗费资源,但一次输入少 
 +  * 链接输入多,但速度快 
 +  * 便于升级(只需要修改需要的文件即可) 
 +===C++ 的编译 / 链接模型=== 
 +C++ 基于分块处理的概念来定义自己的编译链接模型。由此概念引申出了几个重要的概念: 
 +==定义与声明== 
 +  * 变量的问题 
 +    * 如果是简单加工,那么只需要定义一个变量即可 
 +    * 如果是分块处理,那么多个文件中很可能都会使用到这个变量 
 +      * 处理的办法是:**分离变量的定义与声明**,定义只有一处;在**需要使用的地方进行声明** 
 +      * 该定义会在**链接期**进行查找 
 +  * 头文件与源文件 
 +    * 按需声明的做法,在文件较多的情况下也比较费时费力 
 +    * 解决的方法:**将所有的声明装进头文件**,在需要使用的地方**包含该头文件**即可 
 +      * 编译器会将头文件自动展开 
 +  * 翻译单元(编译器处理) 
 +    * 用于处理源文件和头文件的关系 
 +    * 将某个源文件,以及相关的头文件,除开应该忽略的预处理语句,构造出来的东西。 
 +  * 一处定义原则 
 +    * 要求**所有**的翻译单元里只能有**一个定义**(因为编译器必须要看到定义才能编译) 
 +    * 程序级:函数 
 +    * 翻译单元级:内联函数,类,模板 
 +==编译链接模型== 
 +  * **预处理**(//preprocessor//) 
 +    * 将源文件变为翻译单元( ''.i'' 文件) 
 +    * 防止头文件被循环展开:嵌套的头文件会在预处理过程中反复展开 
 +      * 使用宏 ''#ifndef'' 解决:重复定义的 Header 会被当做可丢弃的预处理语句。 
 +        * 缺点:宏重名可能导致引入失败 
 +      * 使用 ''#pragma once'':对展开进行计数
  
-  三种程范式面向过、面向对象、泛型 +<code bash> 
-  函数载、异处理、引用+g++  -E ./main.cpp o ./main.i 
 +</code> 
 +  * **编译**(//Compiler//将翻译单元转换为相应的汇编语言,并进行相应的优化(''-O3'') 
 +    * 优化的缺点:可能使 debug 的信息丢失, 因此会将序编译分为 realease 编译(速度)和 debug 编译(调试) 
 +    增量编译:单独修改某个文件后进行编译,也就是根据源文件的最新时间来判断 
 +      * 如果修改了头文件,那么应该新编译所有的源文件(某些老编译器不支持,此时需要全部编译) 
 +    * 全部编译(//rebuild//):改完头文件后没有 自动 rebuild,那么就需要手动 rebuild 
 +<code bash> 
 +g++ main.i -S - o main.s 
 +</code> 
 +  * **汇编**(//assembler//):汇编代码生成为可链接文件 
 +<code bash> 
 +g++  main.s - c- o main.o 
 +</code> 
 +  * **链接**(//Linker//): 
 +    * 整合所有的目标文件 
 +    * 关联声明和定义 
 +    * 生成可执行文件 
 +    * 链接的种类: 
 +      * 内部链接:如果变量只能存在翻译单元里面,那么是内部链接 
 +      * 外部链接:如果可以存在于翻译单元之间,那么是外部链接(''extern'') 
 +      * 无连接:都不可见,则无连接 
 +    * 见链接错误:定义不可见(比如有声明没定义的情况) 
 +    * 查看当前程序的外部链接:''nm target.o - o''