0%

1、寻址

寻址方式

寻找操作数的地址的各种方式。

1.立即寻址

直接使用操作数将操作数存入相关地址中

1
2
MOV R0,#26H
MOV DPTR,#2000H
  • 立即数可以是8位或16位
  • 立即数前必须加#

2.直接寻址

将操作数视为地址,并将该地址存储的数据转递到相关地址中。

1
MOV A,30H //相当于对30H进行解引用,将30H值传入A中

3.寄存器寻址

直接使用寄存器名字作为地址并对进行解引用

1
MOV A,R1 //*R1

4.寄存器间接寻址

指定寄存器的内容为操作数的地址,该地址存储的内容才是操作数

1
MOV A,@R0 // @R0相当于**R0
  • 需使用间址符@
  • 对外部RAM进行读取时必须采用该方式

5.变址寻址

通过对基地址进行偏移获得当前操作数地址

1
2
MOV A,#06H
MOVC A,@A+PC

由于这里(@A+PC)整体应为一个地址,所以这里要对A使用间址符取06H作为地址的偏移量,因此该两行指令的意思为:将(@A+PC)地址中存储的数据传入A中

6.相对寻址

直接以PC作为基地址,只写出相对偏移量,有两种方式:

无条件转移:

1
SJMP 08H //使PC转移至当前PC值+08H(当前PC为下一指令地址)

条件转移:

1
JZ LOP //仅当(A)=0时执行,LOP为标号

7.位寻址

2、指令系统

1.数据传送指令

  • 片内数据传送:MOV 访问内部RAM
  • 片外数据传送:MOVX 访问外部RAM
  • 程序存储器数据传送:MOVC 访问内外ROM

2.数据交换指令

  • 字节交换(全部):

    1
    2
    XCH A,Rn
    XCH A,@Ri //寄存器区只有R0和R1可用作间接寻址
  • 字节交换(低四位):XCHD

  • 字节交换(高低互换):SWAP

3.堆栈操作指令

  • 入栈:PUSH SP先变化再压栈
  • 出栈:POP 先出栈再变化SP

4.算术运算指令

  • 加法
    • 不带进位: ADD
    • 带进位(Cy):ADDC
    • 加一:INC
  • 减法
    • 不带进位:SUB
    • 带进位:SUBB
    • 减一:DEC
  • 乘法:MUL
  • 除法:DIV

5.逻辑运算指令

  • 逻辑与:ANL
  • 逻辑或:ORL
  • 逻辑异或:XRL
  • 取反:CPL
  • 清零:CLR
  • 移位
    • 不带进位:RL/RR 左移/右移1位
    • 带进位:RLC/RRC ~

6.位运算

该运算对象仅针对Cy和bit型对象

  • 位传送:MOV
  • 置1:SETB
  • 清0:CLR
  • 取非:CPL
  • 取与:ANL
  • 取或:ORL

7.控制转移类指令

  • 无条件转移:LJMP 3字节,直接转移至该16位地址

  • 相对转移:SJMP

  • 条件转移:(条件转移皆为相对PC的转移)

    • 累加器判0:JZ/JNZ

    • 进位Cy判断:JC/JNC

    • 任意位判断:JB/JNB/JBC

      1
      2
      JB bit,rel
      // bit: 判断位 rel:偏移量
    • 比较不相等判断(不相等为满足条件):CJNE

      1
      CJNE A,#data,rel
  • 减1不为0判断转移:DJNZ

try语句与异常处理

通常的异常处理包括三部分:

  • throw表达式:使用throw表达式表示当前程序遇到了某个问题(异常声明)
  • try语句块:与catch配合用于处理各类异常声明
  • 一套异常类:用于传递具体的异常信息(异常声明的含义)

例程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<iostream>
#include<windows.h>
#include <stdexcept>
using std::vector;
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::runtime_error;
int main()
{
int a,b;
cin>>a>>b;
try
{
if(a!=b) throw runtime_error("ERROR!!!");
cout<<"good"<<endl;
}
catch(runtime_error err)
{
cout<<err.what();
}
system("pause");
return 0;
}

throw表达式

1
if(a!=b) throw runtime_error("ERROR!!!");

格式:throw+异常类+初始化异常类对象

  • 该初始化的对象只用于提供一些关于异常的辅助信息(用户自行定义)

  • 异常类为一系列在库中定义的类型,使用时需要声明其命名空间,以下是几种常用的异常类,在头文件stdexcept中

    | exception | 一般错误 |
    | :——————-: | :————————————————————: |
    | runtime_error | 运行时才能检测出的任务 |
    | range_error | 运行时:生成结果超出有意义的值域范围的错误 |
    | overflow_error | 运行时:计算上溢错误 |
    | underflow_error | 运行时:计算下溢错误 |
    | logic_error | 程序逻辑错误 |
    | domain_error | 逻辑错误:参数对应的结果不存在 |
    | invalid_error | 逻辑错误:无效参数 |
    | length_error | 逻辑错误:超出对象类型长度 |
    | out_of_range | 逻辑错误:超出有效范围 |

    • 除exception外其他类型都必须用一个字符串初始化,而exception则不允许这种初始化

      1
      2
      3
      4
      5
      6
      7
      8
      9
      try
      {
      if(a!=b) throw exception();
      cout<<"good"<<endl;
      }
      catch(exception)
      {
      cout<<"ERROR!!";
      }

try语句块

格式:

1
2
3
4
5
6
try
{ }//程序正常逻辑,异常类在此throw出
catch(异常声明)
{}
catch(异常声明)
{}
  • 当try内一旦提出异常类时,就不再执行该throw表达式后的内容;反之,若没有throw任何异常,则不会触发任何catch语句,程序正常执行完try语句。
  • catch括号中需定义一个对象,类型为触发的异常类,这些异常类只有一个子函数what,用于输出初始化时的字符串(不能用于exception类)

当有多个try语句块嵌套时,当最内部try提出了一个异常,会由内到外执行catch,若最终都没有对应catch,则程序转到terminate的标准库函数,该函数行为与系统有关,通常执行该函数会导致程序非正常退出。

函数

参数传递

  • 形参实参之间的转递为值拷贝
  • C++中建议用引用类型的形参代替指针形参,引用类型同样可以达到修改值的内容,并且可以避免拷贝,因为引用是与实参绑定的。

数组的传递

以下三种对形参的定义是等价的:

1
2
3
void a(const int*);
void b(const int[]);
void c(const int[10]);

编译器在编译时只会检查传入的参数类型是否为const int*型,甚至不会检查传入数组的长度是否超出形参大小。

数组的引用形参

可以使用数组的引用作为形参:

1
2
3
4
5
void test(int (&arr)[10])
{
for(auto elem : arr)
cout<<elem<<endl;
};

使用数组的引用作为形参需要注意:

  • 初始化时必须使用括号括起&arr
  • 输入的实参必须为一个int [10]类型的对象

函数的返回类型

返回引用

函数返回引用可以理解为返回的为一个地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char test1(string s ,string::size_type num)
{
return s[num];
}
char &test2(string &s ,string::size_type num)
{
return s[num];
}

int main()
{
srting s("test");
cout<<test1(s,0)<<endl; //t
test2(s,0)='a';
cout<<s[0]<<endl; //a
return 0;
}

当一个函数的返回值为引用时,该返回值为左值而非右值,因此可以像使用其他左值一样使用这个返回值

(注:左值≠地址,它仍然是一个值)

  • 不可返回局部变量的引用,由于局部变量在函数完成后会被释放,因此在函数完成后引用会找不到它的对象。例如上一个例程,如果把test2()函数改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    char &test2(string s ,string::size_type num)//此处形参不再是引用
    {
    return s[num];
    }
    int main()
    {
    srting s("test");
    test2(s,0)='a';
    cout<<s[0]<<endl; //t
    return 0;
    }

    该函数的返回值为对s的引用,但s本身为一个局部变量,在函数完成时已经被释放,因此该引用是无效的(但是这样返回形参的引用编译器并不会报错,而返回函数内定义的局部变量的引用会报错)

    但如果形参定义为引用,由于引用本身是不占用存储空间的,所以’a’可以通过引用直接向s[0]赋值

返回数组指针

  • 尾置返回类型

    1
    auto func(int i) -> int(*)[10]

    声明函数的返回值为一个含有十个整数的数组的指针

  • 使用decltype

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int test[5]={1,2,3,4,5};
    decltype(test) *func()
    {
    return &test;
    }
    int main()
    {
    cout<<*(*func+1); //输出2
    return 0;
    }
    • decltype(test)的结果是一个数组,因此函数前要用*声明返回值为指针
    • 使用此方法返回的是一个数组的整体地址,而不是首地址,类型为int*[5],因此一次解引用的结果才是首地址

内联函数

正常的调用函数一般比等价的表达式要慢(保存寄存器、拷贝等操作),因此对于规模较小的函数可以定义为内联函数类型:

1
2
3
4
inline int fuc(int a,int b)
{
return a+b;
}

constexpr函数

将函数隐式地定义为内联函数,但函数内只能有一条return语句,且返回值必须为字面值

1、基础内容

表达式是由一个或多个运算对象组成,对表达式求值得到的是一个结果,字面值和变量时最简单的表达式。

左值和右值

当一个对象被用作右值时,使用的是该对象的值;而被用作左值时,使用的时对象的内存。

  • 赋值运算符需要一个非常量左值为其左侧运算对象
  • 取地址符作用于一个左值运算对象,返回一个指向该运算对象的指针,该指针为右值
  • 解引用求值结果为左值

求值顺序

部分运算符是没有明确指明执行顺序的,例如<<运算符:

1
cout<<i<<""<<++i;

++i和i没有明确的先后关系,因此编译器可能做出任何行为。

当多个函数会影响同一对象时,当同时调用这些函数时,调用函数的顺序也没有明确的先后关系。

2、算术运算符

bool类型

bool类型原则不应参与运算,在运算时会自动转化为int型的1,只要计算结果不为0,都将返回ture

优先级

C++大部分同优先级运算都满足从左至右的规律,赋值则相反

递增运算

C++中,非必要不使用后置递增/减符(i++/i—),因为前置运算为将对象本身作为左值返回,而后置则要额外的空间存储原始值,并将这个额外存储的原始值副本作为右值返回,因此,使用后置操作会消耗更多内存,这在相对复杂的工作中是消耗巨大的。

位操作

关于符号位的处理没有明确规定,因此位运算最好用来处理无符号类型

3、类型转换

C++的类型转换格式不同于C:

1
cast-name<类型>(表达式)

最常用的cast-name为static_castconst_cast

static_cast

任何有明确定义的类型转换(除了底层const)都可以使用static_cast

例:

1
2
void *p = &d;//d不能为常量(底层const)
double *dp = static_cast<double*>(p);

const_cast

专用于改变底层const,其作用为改变const性质

1
2
const char* pc;
char *p=const_cast<char*>(pc);

需要注意,可以有以下用法:

1
2
char* pc;
char *p=const_cast<const char*>(pc);