zoukankan      html  css  js  c++  java
  • c++--essence

    1 环境

     

    1.1 windows 10 + visual studio 2019

     

    1.1.1 主题设置

    1. 点击 工具(菜单)->选项
    2. 点击 环境->常规,选择相应的主题之后确定

    1.1.2 字体设置

    1. 点击 工具(菜单)->选项
    2. 点击 环境->字体和颜色,选择相应的内容之后确定

    1.1.3 语言设置和添加

    • 选择语言
      1. 点击 工具(菜单)->选项
      2. 环境->区域设置右侧选项选择之后确定
    • 添加语言
      1. 点击 工具(菜单)->获取工具和功能,进入安装配置界面
      2. 点击 语言包(菜单),勾选要添加的语言
      3. 点击 修改(右下角),等待下载安装(根据提示操作,可能需要重启软件)

    1.1.4 文本格式配置(自动使用 utf8)

    • 安装扩展 ForceAllUtf8
      1. 点击 扩展(菜单)->管理扩展
      2. 在 联机->搜索(在右上角位置) 中输入需要安装的东西
      3. 选中要安装的内容,点击安装,点击 关闭
      4. 关闭应用程序,按提示安装

    2 一些汇编知识点

     

    2.1 栈区、堆区、代码区、全局区一些知识

    • 编译好的函数代码在代码区,代码区是只读的(受保护的)
    • 执行函数时为函数分配栈空间,用于保存局部变量,分配的栈空间有个首地址,局部变量使用这个地址加偏移地址来访问(如:ebp-0cH)

    2.2 一些简单指令

    /*
    左边机器码,右边汇编指令,一一对应
    机器码和CPU架构有关,编译器根据不同平台编译,虽然不一样,但是形式应该差不多
    一般都是借助寄存器中转,来修改内存地址
    [xxx] xxx 一般都代表某个地址
    mov 读写寄存器和地址的内容
    add +
    sub -
    inc ++
    dec --
    lea 装载地址
    
            int a = 2;
    C7 45 F8 02 00 00 00 mov         dword ptr [ebp-8],2  //2 保存到 ebp - 8 指定的地址
            int b = a + 2;
    8B 45 F8             mov         eax,dword ptr [ebp-8]  //ebp-8地址的内容保存到eax寄存器中
    83 C0 02             add         eax,2  //eax 寄存器 + 2
    89 45 EC             mov         dword ptr [ebp-14h],eax  //将寄存器的内容保存到 ebp - 14 指定的内存地址
            int c = a + b;
    8B 45 F8             mov         eax,dword ptr [ebp-8]  //quard 是4个字节,dword 是2个字节
    03 45 EC             add         eax,dword ptr [ebp-14h]  
    89 45 E0             mov         dword ptr [ebp-20h],eax  
            int d = c + 1;
    8B 45 E0             mov         eax,dword ptr [ebp-20h]  
    83 C0 01             add         eax,1  
    89 45 D4             mov         dword ptr [ebp-2Ch],eax  
            int e = c - 1;
    8B 45 E0             mov         eax,dword ptr [ebp-20h]  
    83 E8 01             sub         eax,1  
    89 45 C8             mov         dword ptr [ebp-38h],eax  
            int f = e - 2;
    8B 45 C8             mov         eax,dword ptr [ebp-38h]  
    83 E8 02             sub         eax,2  //相减
    89 45 BC             mov         dword ptr [ebp-44h],eax 
    
    
            int a = 2;
    C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
            int* p = &a;
    保存地址ebp-0Ch(a的地址)到eax中
    8D 45 F4             lea         eax,[ebp-0Ch] 
    保存eax中的内容到 ebp - 18h 地址中
    89 45 E8             mov         dword ptr [ebp-18h],eax               mov         dword ptr [ebp-18h],eax
            *p = a;
    8B 45 E8             mov         eax,dword ptr [ebp-18h]
    8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]
    89 08                mov         dword ptr [eax],ecx
    
    int sum(int v1, int v2, int *p) {
            return v1 + v2 + *p;
    }
    
            int a = 2;
    C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
            int* p = &a;
    8D 45 F4             lea         eax,[ebp-0Ch]
    89 45 E8             mov         dword ptr [ebp-18h],eax
            int b = sum(a, 3, p);
    将ebp-18h(p)地址的内容保存到eax
    8B 45 E8             mov         eax,dword ptr [ebp-18h]
    50                   push        eax
    6A 03                push        3
    8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]
    51                   push        ecx
    E8 C3 D0 FF FF       call        003613B1
    
    
            return v1 + v2 + *p;
    8B 45 08             mov         eax,dword ptr [ebp+8]
    03 45 0C             add         eax,dword ptr [ebp+0Ch]
    将ebp+10h地址的内容保存到 ecx
    将eax 中的内容和ecx中的地址中的内容相加,保存到eax中
    mov eax dword ptr [xxx]
    mov eax dword ptr [ecx]
    8B 4D 10             mov         ecx,dword ptr [ebp+10h]
    03 01                add         eax,dword ptr [ecx]
    */
    

    3 C++ 知识点

     

    3.1 输入、输出

    #include <iostream>
    using namespace std;
    //输入完成会自动换行
    //内容如果有空格会截断,当成下一次输入的内容
    int main() {
            int age = -1;
            cout << "please input age:";
            cin >> age;
            cout << "age is:" << age << endl;
            getchar();//抵消回车
            getchar();//阻塞代码,等待输入,用于查看结果
            return 0;
    }
    

    3.2 函数默认参数

     

    3.2.1 简单例子

    int sum(int v1 = 10) {
            return v1;
    }
    

    3.2.2 默认参数只能放在最右边

    int sum(int v1, int v2 = 20) {
            return v1 + v2;
    }
    int sum(int v1, int v2 = 20, int v3 = 30) {
            return v1 + v2 + v3;
    }
    

    3.2.3 函数同时有声明和实现,默认参数只能放在声明当中

    #include <iostream>
    using namespace std;
    int sum(int v1 = 10);
    
    int main() {
            cout << sum() << endl;
            getchar();
            return 0;
    }
    
    int sum(int v1) {
            return v1;
    }
    

    3.3 函数重载

     

    3.3.1 参数精确匹配

     
    1. 参数个数不同
      int sum(int v) {
              return v;
      }
      int sum(int v1, int v2) {
              return v1 + v2;
      }
      
    2. 类型不同
      int sum(int v) {
              return v;
      }
      int sum(double v) {
              return v;
      }
      
    3. 顺序不同
      int sum(int v1, double v2) {
              return v1 + v2;
      }
      int sum(double v1, int v2) {
              return v1 + v2;
      }
      

    3.3.2 错误示例

     
    1. 由于C++编译器使用 name decorate,改变了函数的名称,C中函数名不变,不支持重载
    2. 仅返回值不同
      int sum(int v) {
              return v;
      }
      double sum(int v) {
              return v * 1.0;
      }
      
    3. 隐式提升
      int sum(long v) {
              return v;
      }
      int sum(double v) {
              return v;
      }
      
      ......
      sum(10);
      ......
      
    4. 默认参数导致匹配到多个函数,产生二义性
      int sum(int v1) {
              return v1;
      }
      int sum(int v1, int v2 = 20) {
              return v1 + v2;
      }
      ......
      sum(1);
      ......
      

    3.3.3 函数默认参数本质

    函数调用时,不传默认参数和传入默认参数编译的结果是一样的(机器码基本一样)

    3.4 extern "C"

    要求以C的方式编译

    3.4.1 修饰单行

    extern "C" int sum(int v1) {
            return v1;
    }
    

    3.4.2 修饰块

    extern "C" {
            int sum(int v1) {
                    return v1;
            }
    }
    

    3.4.3 同时有声明和定义,修饰声明(定义也可以同时修饰,不推荐同时修饰)

    #include <iostream>
    using namespace std;
    
    extern "C" {
            int add(int a, int b);
            int mul(int a, int b);
    }
    
    int main() {
            getchar();
            return 0;
    }
    
    int add(int a, int b) {
            return a + b;
    }
    int mul(int a, int b) {
            return a * b;
    }
    

    3.4.4 使用场景

    C、C++ 混合开发

    1. 一般都是把声明写到头文件中(假设库文件为 xxx.c,用C来编写的文件)
      1. 头文件引入写法
        1. 标准库
          #include <xxx>
          
        2. 第三方库
          #include "xxx.h"
          
      2. C++ 引入形式
        extern "C" {
                int sum(int v);
        }
        
      3. C 引入形式

        由于以 C 的方式编译不认识 extern "C",就是简单的函数声明

        int sum(int v);
        
      4. xxx.h 文件同时满足两种引入方式

        利用 C++ 编译器内置的宏 __cplusplus 来进行条件编译

        #ifdef __cplusplus
        extern "C" {
        #endif // __cplusplus
        
                int sum(int v);
        
        #ifdef __cplusplus
        }
        #endif // __cplusplus
        
      5. 同一头文件保证一次引入

        引入相当于简单替换,多次引入会浪费编译资源

        1. 使用 #ifdef #ifndef #endif 的方式

          利用宏名称减少冲突率概,灵活,可以根据需要包含相应的内容,编译器支持这个标准

          #ifndef __TEST_H
          #define __TEST_H
          
          
          #ifdef __cplusplus
          extern "C" {
          #endif // __cplusplus
          
                  int sum(int v);
          
          #ifdef __cplusplus
          }
          #endif // __cplusplus
          
          #endif // !__TEST_H
          
        2. 使用 #pragma once 的方式

          整体保证一次编译,需要新的编译器支持

          #pragma once
          
          #ifdef __cplusplus
          extern "C" {
          #endif // __cplusplus
          
                  int sum(int v);
          
          #ifdef __cplusplus
          }
          #endif // __cplusplus
          
          
    2. 头文件对应的实现文件一般也会引入头文件

      实现有先后顺序,后面的可能会使用前面的东西,引入头文件就不用考虑位置顺序了

    3.5 inline function (内联函数)

     

    3.5.1 用法

    inline 关键字很随意,可以放在声明,也可以放在定义,都写也可以(推荐)

    inline int sum(int a, int b) {
            return a + b;
    }
    

    3.5.2 特点

    • 是否应用取决于编译器
    • 函数内容一般不超过10行
    • 有递归等的复杂函数是不会有效果的
    • 具有函数特性和一般函数一样使用(会进行语法检查),编译时会替换

    3.5.3 本质(不考虑编译器优化)

    • 函数调用的地方直接用函数体进行替换
    • 可以减少函数调用栈的开销,提高效率
    • 会增大代码体积(执行文件变大)

    3.6 宏替换

    直接进行替换,用于计算很容易出问题

    #define sq(a) (a) + (a)
    
    ......
    int a = 10;
    sq(++a); //24
    //++a + ++a; //替换成这样
    ......
    

    3.6.1 表达式赋值

     
    1. C 中不支持
      1. 三元运算符
        int a = 1;
        int b = 2;
        a > b ? a : b = 100;
        

    3.7 const

     

    3.7.1 指针常量

    指针指向的内容不能改

    int a[] = { 1, 2, 3 };
    int b = 100;
    const int* p = a;
    //p[0] = 123; 不能通过 p 来修改 p 指向的内容
    p = &b; //指针指向的内容新的地址
    

    3.7.2 常量指针

    指针指向不能改

    int a = 100;
    int b = 10;
    int * const p = &a;
    //p = &b; 不能再次赋值 p
    *p = 125; //p 指向的内容可以修改
    

    3.7.3 指向常量的常量指针

    赋值后不变,只能读不能写(三种情况是正常手段下是这样)

    3.8 引用

     

    3.8.1 用法

     
    1. 简单用法
      int a = 100;
      int &ref = a;
      
    2. 用于复杂对象(以结构体为例)
      struct Date{
        int &year;
        int &month;
        int &day;
      }
      

    3.8.2 特点

    • 定义引用时必须初始化
    • 已经定义的引用不能重新指向其他对象

    3.8.3 本质

    编译器将引用转成指针,生成的机器代码和使用指针是一样的(反编译可查看)

    3.8.4 数组的引用

    int arr[] = { 1,2,3 };
    int(&a)[3] = arr;
    //arr 是常量指针
    int* const& b = arr;
    

    3.8.5 const 引用

     
    1. 不能通过引用修改引用或者指针指向的对象
      int val = 123;
      const int& r1 = val;
      int const& r2 = val;
      
      //对比指针写法
      const int* r1 = &val;
      int const* r2 = &val;
      
    2. 可以构成重载函数
      #include <iostream>
      using namespace std;
      
      int sum(int& v1, int& v2) {
              return (v1 + v2) * 2;
      }
      int sum(const int& v1, const int& v2) {
              return v1 + v2;
      }
      int main() { 
              int a = 1;
              const int b = 1;
              sum(a, a); //4
              //const 引用参数匹配
              sum(b, b);
              sum(1, 1); //2
      
              getchar();
              return 0;
      }
      
    3. 指向常量,临时对象(某些表达式返回值、函数返回值)
      const int $fa = 123;
      const int a = 123;
      const double &fb = a;
      

    3.8.6 不存在引用的引用

    引用相当于引用对象的别名,引用没有开辟内存空间,再次引用对象是同一个对象

    Created: 2019-12-13 周五 18:04

    Validate

  • 相关阅读:
    poj 2109Power of Cryptography
    poj 2632Crashing Robots
    poj 2586Y2K Accounting Bug
    linux0.12中文件系统的一些理解
    latex初学者的经验
    关于linux0.12中的add_entry中bread中的些猜测
    uid gid euid egid详解
    关于linux0.12文件系统目录大小的一个发现
    我的初级muttrc配置
    使用STM32的USB模块中后对USB缓冲区的认识
  • 原文地址:https://www.cnblogs.com/heidekeyi/p/12010885.html
Copyright © 2011-2022 走看看