ObjectiveC-03-XCode的使用和基础数据类型

news2024/12/29 8:37:29

本节做为Objective-C的入门课程,笔者会从零基础开始介绍这种程序设计语言的各个方面。

术语

  • ObjeC:Objective-C的简称,因为完整的名称过长,后续会经缩写来代替;
  • 项目/工程:也称工程,指的是一个App的源文件的文件夹包和结构,有时也称为工程或项目工程。
  • 项目模板:不只ObjC,用不同编程语言开发App时其源码都会包含源文件、集成框架、配置文件、资源图片等,这些元素需要放在同一个文件中并要符合某种规则,而针对不同类型的App其元素和组织又不一样,这个工作比较费时,所以为了效率考虑一般会经一个母版进行修改,这个母版就称为项目模板;

Command Line Tool工程

首先,我们需要创建一个Command line tool工程项目(即不带图形化界面的项目)。
在这里插入图片描述
在上述工程创建界面上有很多模板项目,可以按需要选择相应的模板开发,这样省去了好多搭建框架的时间,但也可以选择从空项目开始。多数模板可以从字面意思就可以了解。

  • 现在我们只需要知道Command Line Tool工程模板就足够了(一种无UI界面的可在命令行执行的脚本工程模板);
  • 后续在涉及AppKit之前的所有代码我们全会以这类工程为载体演示代码,其它的工程模板在讲到其内容时再详细解释。

创建HelloWorld工程

按照惯例,我们还是以一个Hello Word项目做为开始,了解一下ObjC(ObjectiveC简称)项目结构和基础语法。项目名称暂时称为helloWorld,项目设置采用默认即可,不需要做任何改变,项目结构如下:

在这里插入图片描述

打开main.m文件,我们所有的测试代码暂时全写在这里面,.m是ObjC代码文件的后缀(.c是C语言的源码文件),运行时会交由程序编译器LLVM处理和运行。

//
//  main.m
//  helloWorld
//
//  Created by 刘东 on 2023/12/20.
//

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool { // 自动释放池,由系统来管理变量的内存
        // insert code here...
        NSLog(@"Hello, World!"); // 打包日志函数,用@修饰表示NSString对象
    }
    return 0;  // 规定 0 表示程序正常结束,其它值都是非正常结束
}

除了上述.m文件外还可以兼容几下以类源码文件:

  1. .c:C文件
  2. .cc, .cpp:C++文件
  3. .h:头文件
  4. .mm:Objective-C++文件,可以同时使用ObjectiveC和C++语法;
  5. .pl:Perl文件
  6. .o:ObjectiveC编译后的文件
  7. .m:Objective-c文件

代码注释

在ObjC中只有两种注释:

  • //:行注释,一般用于代码行或代码后面;
  • /* */:块注释,一般用于类说明,方法说明或代码块说明使用;
  • #pragma mark *** String funnel methods ***,这是一种特殊格式的指令,也能起到注释的作用,详细可参考代码导航一节;
// Secondary text that may be displayed

/*
 Secondary text that may be displayed adjacent to or below the primary title depending on the configuration of the window.
 A value of empty string will remove the subtitle from the window layout.
*/

模块导入

格式为:#import <Foundation/Foundation.h> 注意最后面没有;分号,表示为当前类的实现添加相关的模块依赖。如果导入的是自定义的实现,则需要用双引号(本地)替换<>(系统)。

#import <Foundation/Foundation.h>
#import "Fraction.h" 

上述所谓的系统其实称为框架更合适,比如Foundation、AppKit框架,每个框架都有一个主头文件,它包含了框架内所有的头文件,只需导入一次就可以使用此框架内所有的功能,这样就省去了一个个导入的麻烦。

MAC OS所有框架的目录位于 /System/Library/Frameworks 目录下。

入口函数main

程序运行的主入口函数,格式为:int main(int argc, const char * argv[]),程序的执行入口和java的main函数功能相同,每个App最多只能允许存在一个main函数。一般练习时用main函数调用就行,如果是大型项目ObjC也提供了专门的单元测试框架,后续会讲到,main.m语法格式如下:

static void method(){
}

/*
argc:命令行输入的参数个数
argcv:字符指针数组,即参数值
*/
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //代码位置
    }
    return 0;
}

运行传参

函数说明:int main(int argc, const char * argv[])

  • argc:命令行输入的参数个数
  • argcv:字符指针数组,即参数值,argcv[0]指向一个函数,argcv[1]为一个字符数组
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        struct entry dict[100] = {
            {"abyss", "a bottomless pit"},
            {"addle", "to become confused"}
        };
        
        int entries = 10;
        int entryNumber;
        int lookup(struct entry dict[], char search[], int entries);
        
        if (argc!=2){
            NSLog(@"no word typed on the command line.");
            return 1;
        }
        
        entryNumber = lookup(dict, argv[1], entries);
        if(entryNumber!=-1){
            NSLog(@"%s", dict[entryNumber].definition);
        }
    }
    return 0;
}

调用方法如下,可从命令行,也可从Xcode中执行

clang -fobjc -arc main.m lookup abyss - 

上述程序会调用函数lookup,然后在dict字典中查找argv[1]中的单词,如果找到就返回详细的解释。

添加函数

在main函数所在的类中也可以添加自定义的方法,但方法的命名方式和ObjC的语法有很大不同,这一点需要额外注意。在main中定义的方法是C语言的语法。

#import <Foundation/Foundation.h>

//无参方法,在方法前面也可以添加static关键字
void nsRangeTest(){
    NSRange range1 = {17, 4};
}

//有参方法
NSComparisonResult *compareArray(id element, id compareEle){
    return [[compareEle name] compare: [element name]];
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        nsRangeTest();
    }
    return 0;
}

打印函数NSLog

打印函数,相当于C语言或JAVA语言的print()函数,这里需要注意写法,一定是以@开头,这也说明了NSLog函数的入参是一个NSString类型的对象(在ObjC语言中,字符串用@""表示),另外所有的Cocoa函数和对象全部以NS做为命名前缀(也被称命名空间),也有一些老的API是采用CF开头的但不建议使用了。

NSLog(@"Hello, World!");
int sum = 20+25;
NSLog(@"The sum is %i", sum); //NSLog函数如果发现%,则视为占位符,这样的占位符有很多,后续会讲到

也可以用printf()函数来代码,但不是太建议,因为NSLog添加了很多格式化的信息,注意看下面代码的输出

        NSLog(@"Hello, World!\n");
        printf("Hello, World!\n");
        
        ~~~~
        2024-03-26 19:31:52.091265+0800 helloWorld[46546:5251675] Hello, World!
        Hello, World!

键盘输入

scanf()函数也可以使用占位符,因为键盘接收的原始数据全是字符串,在程序中需要做一些类型转换工作。下在程序运行后在scanf处会卡住,然后在控制台输入相应字符后就会往下执行了。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age;
        scanf("%i", &age); //注意&的用法,它表示一个指针引用,
        NSLog(@"age is %i", age);
    }
    return 0;
}

/*~~
aaa
2024-03-27 14:39:56.103878+0800 objcBase[59017:6048518] age is 32759
Program ended with exit code: 0
*/

程序运行

除了使用Xcode工具运行,还可以使用命令行工具执行。其命令如下,其中prog1为重命名的项目名称。但这种方式并友好,因为还在设置PATH等资源目录。

(base) MacBook:~ liudong$ clang -fobjc-arc main.m -o prog1

(base) MacBook:~ liudong$ clang -fobjc-arc -framework Foundation main.m -o prog1

输入类似下面的界面:
在这里插入图片描述
用NSLog输出时,上面的4596表示当前应用的进程ID号。另外编译好的文件一般会存放在以下目录中,其中helloWorld-ghwqfuwptpnvhtfpzqoxxzcbnzow是一串随机值。不同版本的OS操作系统存放的位置有可能不太一样。

~/Library/Developer/Xcode/DerivedData/helloWorld-ghwqfuwptpnvhtfpzqoxxzcbnzow/Build/Products/Debug

进入这个目录下可以执行./helloWorld就可以直接运行应用了。
在这里插入图片描述

程序中止

有两种方式一种是在main函数中中止,一种是在方法中强制中止,在main函数中直接使用retrun 0即可,则在方法中需要使用以下代码。

exit(0);

设置XCode

首先来讲,苹果公司通常喜欢在不同版本的XCode中增加或移动一些功能,而且这些功能对开发代码的效率是非常高的。下面就以XCode V13版本为例来说明下这些设置如何操作。

主界面

在这里插入图片描述

  • 导航器:用来显示项目的源码,最上面的有9个左右的工具栏,包括:符号、搜索、总是、调试、断点和日志等,快捷键盘是command+数字1~9;
  • 工具栏:这里最主要的是库面板,需要从菜单View-Show Toolbar打开;
  • 检查器:不同的文件会有不同的设置,也就是属性设置面板;
  • 代码编辑区:在最上面有一个面包屑栏和工具栏,工具栏上有导航文件功能,面包屑栏显示了当前文件一些内容。这块的功能比较简单,点一次就可以记住了;

环境下载

在Preferences偏好设置中可以下载不同的运行环境:
在这里插入图片描述

代码自动完成

XCode有代码提示功能,输入一个字符会有默认提示,通过ESC键来打开或关闭提示框,然后通过Control+/-可实现快速翻页。
在这里插入图片描述

  • # :代表define指令;
  • m :表示method;
  • f :表示函数;
  • c :表示类

代码导航

可以通过在源码中设置特殊的标识来把需要关心的代码加入到代码面包屑工具栏中,这些标识在编译时会被编译器忽略掉。
在这里插入图片描述
这些特殊标记通常用:

  1. -,减号实现一个分隔线,见上图
  2. whatever,任意字符;
  3. //开头的特殊标记,以关键字+冒号+空格+文字描述格式,比如//TODO: 未完成的工作,这些关键字一般有TODO:、FIXME:、!!!:、???:

快捷键

  1. 鼠标左键+option,然后点击某个类型,在弹出窗口点击相应的类型名可直接跳转到document;

  2. control+i,格式化代码;

  3. command+d,删除行(需要在keymap中搜索delete line自行设置);

  4. command+左/右箭头,快速移到行首和行尾

  5. command+shift+o,快速查找;

  6. command+option+左/右箭头:展开和折叠代码,功能们于Edit-Code Folding下面

  7. command+option+shift+左/右箭头:展开和折叠所有方法

  8. command+r,运行程序

  9. command+u,测试程序

另外可供编辑使用的快捷键盘就是电脑上的触摸屏,可通过Edit-Customizer Touch bar 来设置,如下:
在这里插入图片描述

程序调试

主要使用以下几个工具,依次是:跳到下一个断点、下一行、进入被调用的方法、跳出被调用的方法。分别对应快捷键F5~F8。

在这里插入图片描述

另一个调试窗口在导航区上,与调试区联动,主要是下图中这两个标签页,一个是性能查看,另一个是断点浏览
在这里插入图片描述
鼠标悬浮到某个程序变量上也会显示相应的信息
在这里插入图片描述
还有一些更高级的功能可以在控制台输入相应的指令,比如:

  • call [exp]:调用给定对象的方法;
  • print [exp]:打印表达式的原始值,比如print [int] [obj length];
  • print-object [exp]:打印表达式的对象值;
  • set [v] = [exp]:给表达式赋值;
  • whatis [exp]:判断变量的类型;
  • help:帮助;
    在这里插入图片描述

静态检查器

这个功能是不是一个新的功能,很多IDE都有此种能力,有些还会以插件的形式存在,比如sonna, understand或是idea中的各种分析插件。

静态检查器的功能就是不运行代码来分析代码中可能存在的一些问题,在xcode中其功能集中在菜单"project-Analyze"中,它可以检查代码中的:

  1. 安全问题;
  2. 并发问题;
  3. 逻辑问题;
  4. 冗余代码;
    在这里插入图片描述
    疑似有问题的代码可以在导航面板中查看,找到问题后可在面板中点Fix来修复这些警告信息。
    在这里插入图片描述
    有时也会误报,因为检查器毕竟也是一段逻辑固定的程序,没办法覆盖所有的代码模式,如果发现了语报除了用上面 Fix 来关闭外,也可以在方法后加一个特殊标识来告诉检查器这块的这个问题不要检查了,比如:
//类似这样的标签还有很多,可以按需选择
static void dataFun (void) NS_RETURNS_RETAINED {  }

基础数据类型

基础数据类型

布尔类型

关键字BOOL,其值默认只有YES或NO,在Objc中只可与1和0相互转换,占8位存储空间,在写程序时也可以用#define把TRUE和FALSE定义为1 和 0,示例如下:

BOOL areIn(int thing, int ti){
    if (thing == ti){
        return (YES);
    }
    return NO;
    
    //return thing = ti; 这行代码有问题,因为ObjC中只有0和1来平替YES和NO
}
NSString *bool2Str(BOOL y){
    if (y == YES){
        return @"yes";
    }else{
        return @"no";
    }
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        BOOL *boolV = areIn(1, 2); 
        NSLog(@"%d = %@", boolV, bool2Str(boolV)); //0 = no
        
        NSLog(@"%d = %@", 1, bool2Str(1)); //1 = yes
        NSLog(@"%d = %@", YES, bool2Str(YES)); //1 = yes
        
    }
    return 0;
}

char字符类型

单个字符,用’'单引号表示

char c = 'a';

int整数类型

int i = 1000;

float浮点类型

带小数点的变量,比如

float f = 123.95;

double双精度浮点数

双精度

double d = 8.44e+11;

字符串常量

字符不是一个基本类型,它是一个对象,在使用时除了用对象实例化后,简单的可以直接用@“”,来表示:

NSString *str = @"korgs";
创建一个可变字符串
NSMutableString *stringM1 = [[NSMutableString alloc] initWithString:@"字符串"];

可用cString打印字符串内容,它返回的是一个char *指针地址。

         NSString *string = @"abdc";
         NSLog(@"%@, %s", string, [string cString]);//abc, abc
         NSLog(@"lenght = %i", [string length]);//4

类型限定词

ObjC中的数据类型定义非常有意思,支持组合定义,这些限定词主要包括:long, long long, short, unsigned和signed这几个,它的作用是扩充原有数字的表述范围,具体的范围会根据系统决定,比如

long int factorial; //声明为long的整形变量

long, long long, short, unsigned和signed

类型运算符

  1. 四则运算: +、 -、 *、 \、 %、++、–
  2. -(负号)
  3. 类型强转,这里和java一样, 比如这样的写法 int a = (int)f,f为一float类型
  4. 赋值运算:=、!=、+=、-=、/=、*=
  5. 三元运算符:condition ? expression1: expression2
  6. 位运算:&、 |、 ^、 ~(求反)、 << 、>>
  7. 关系运算:==、!=、< 、 > 、 <= 、 >=

运算规则

主要是数值上面:

  • 同类型的的数相互运算,结果是同类型;
  • bool, char, short, int, bit field, enum全部转为int再运算;
  • 大类型与小类型运算结果为大类型,比如long int / short int = long int;

数据打印

以上类型如果需要用NSLog等函数打印时,其占位符表示都不太一样,大体如下。当用%@时表示可以打印任何内容。看似很复杂,其实就四个特殊的,float, long, unisigned, long long,分别用f, l(L), u(U), ll(LL)来表示,其它的不是太常用

类型实例示例NSLog字符
char‘a’ ‘\n’%c
short int123%hi, %hx, ho
unsigned short int123%hu, %hx, %ho,%hx
int12, -97, 0177(8进制)0xFEE0(16进制)%i, %x, %o
unsigned int12u, 100U, 0xFFU%x, %0, %u
long int12L, -2001, 0xFFFFL%li, %lx, %lo
unsigned long int12UL, 100ul, 0xFFFFUL%lu, %lx, %lo
long long int500ll, 0xe5e5e5LL%llu, %llx, %llo
float12.32f, 3.1e-5f%f, %e, %,g, %a
double12.32, 3.1e-5%f, %e, %g, %a
long double12.34L, 3.1e-5l%Lf, %Le, %Lg
idnil%p
**p(指针)%@
  1. %@:是一个通用字符可表示任何数据,可归类为打印对象,它会调用类的description:方法;
  2. %s:打印字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1563995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记某客户的一次无缝数据迁移

背景 客户需要将 Elasticsearch 集群无缝迁移到移动云&#xff0c;迁移过程要保证业务的最小停机时间。 实现方式 通过采用成熟的 INFINI 网关来进行数据的双写&#xff0c;在集群的切换恢复过程中来记录数据变更&#xff0c;待全量数据恢复之后再追平后面增量数据&#xff…

Node.js------Express

◆ 能够使用 express.static( ) 快 速 托 管 静 态 资 源◆ 能够使用 express 路 由 精 简 项 目 结 构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念&#xff…

Discuz! X3.5苗木_苗木网_苗木价格_苗木求购信息_苗木批发网模板utf-8

适合做苗木行业平台苗木网站、苗木信息网,提供苗木报价、各地苗木求购信息、绿化苗木采购招标、苗木基地展示、苗木百科知识、花木交易及苗木资讯、各地苗木信息网络行情。解压上传到template目录下&#xff0c;后台安装即可&#xff0c;包含PC手机端模板 下载地址&#xff1a;…

Windows 上路由、端口转发配置,跨网络地址段

一、背景 有时候我们会遇到这样的场景&#xff0c;一批同一局域网中只有某一台主机带外且系统为windows&#xff0c;局域网中其他非带外的主机要想访问外网&#xff0c;本文将介绍如何配置在带外主机上开启路由及端口转发。 二、配置操作 2.1、带外主机开启路由转发 1&#x…

QA测试开发工程师面试题满分问答6: 如何判断接口功能正常?从QA的角度设计测试用例

判断接口功能是否正常的方法之一是设计并执行相关的测试用例。下面是从测试QA的角度设计接口测试用例的一些建议&#xff0c;包括功能、边界、异常、链路、上下游和并发等方面&#xff1a; 通过综合考虑这些测试维度&#xff0c;并设计相应的测试用例&#xff0c;可以更全面地评…

一文盘点Mendix在SAP之上的那些事儿

前言 近来接手了2个与SAP有关的低代码案子&#xff0c;客户都会问Mendix和SAP之间怎么回事。 2017年开始Mendix 成为SAP Endorsed APP级别合作伙伴&#xff0c;并再度升级为Solution Extension最高级别。 两家公司风雨同舟七载&#xff0c;服务的全球大客户不胜枚举。 商业…

【嵌入式智能产品开发实战】(十四)—— 政安晨:通过ARM-Linux掌握基本技能【链接静态库与动态库】

目录 链接静态库 动态链接 与地址无关的代码 全局偏移表 延迟绑定 共享库 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 嵌入式智能产品开发实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论…

穿什么有这么重要?--装饰模式

1.1 穿什么有这么重要&#xff1f; 约会穿什么&#xff1f; "那要看你想给人家什么印象&#xff1f;是比较年轻&#xff0c;还是比较干练&#xff1b;是比较颓废&#xff0c;还是要比较阳光&#xff1b;也有可能你想给人家一种极其难忘的印象&#xff0c;那穿法又大不一样…

算法错题本

这里写目录标题 错题本注意数据的耦合性对于无解情况的处理思路一组数据以0为结束标记&#xff0c;如何输入到数组中&#xff0c;并计数多个数据进行比较链表删除重复元素的启发循环体里谨慎写类型定义并初始化&#xff08;一般写上就是错&#xff09;队列中读取队尾元素数组当…

基于ssm的三省学堂-学习辅助系统(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的三省学堂-学习辅助系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 三省学堂-学习辅助系统的…

深入理解数据结构第二弹——二叉树(2)——堆排序及其时间复杂度

看这篇前请先把我上一篇了解一下&#xff1a;深入理解数据结构第一弹——二叉树&#xff08;1&#xff09;——堆-CSDN博客 前言&#xff1a; 相信很多学习数据结构的人&#xff0c;都会遇到一种情况&#xff0c;就是明明最一开始学习就学习了时间复杂度&#xff0c;但是在后期…

回顾快速排序

快速排序 快速排序的核心&#xff1a; 找到一个key 通常左边的数比key小&#xff0c;右边的数比key大。 找key通常有三种方法&#xff1a; 1. 挖坑法&#xff1a; 代码实现&#xff1a; // int _pivot(int* a, int left, int right) {int begin left, end right;int in…

开源AGV调度系统OpenTCS中的任务分派器(dispatcher)详解

OpenTCS中的任务分派器dispatcher详解 1. 引言2. 任务分派器(dispatcher)2.1 默认的停车位置选择2.2 可选停车位置属性2.3 默认的充电位置选择2.4 即时运输订单分配 3. 默认任务分派器的配置项4. 参考资料与源码 1. 引言 openTCS是一项著名的开源运输控制系统&#xff0c;我在…

Go 源码之 Chan

Go 源码之 chan go源码之chan - Jxy 博客 目录 Go 源码之 chan一、总结二、源码&#xff08;一&#xff09;hchan&#xff08;二&#xff09;创建&#xff08;三&#xff09;发送&#xff08;四&#xff09;接收&#xff08;五&#xff09;关闭 三、常见问题1.为什么要使用环形…

[Linux] 排查问题指令top/ps/netstat

在Linux下查看某个端口运行的指令 1. 首先通过netstat来查看端口对应的进程号 比如抓取端口53这个DNS服务的进程 netstat -tulnp | grep 53 可以看到53这个端口号对应的pid是720 2. 通过ps指令来对进程号执行的命令查询 ps aux | grep 720 可以看到pid为720这个进程对应的执…

Android APP代码混淆技术解析与实战指南

Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆&#xff0c;使得反编译出来的代码很难阅读和理解&#xff…

【中文视觉语言模型+本地部署 】23.08 阿里Qwen-VL:能对图片理解、定位物体、读取文字的视觉语言模型 (推理最低12G显存+)

项目主页&#xff1a;https://github.com/QwenLM/Qwen-VL 通义前问网页在线使用——&#xff08;文本问答&#xff0c;图片理解&#xff0c;文档解析&#xff09;&#xff1a;https://tongyi.aliyun.com/qianwen/ 论文v3. : 一个全能的视觉语言模型 23.10 Qwen-VL: A Versatile…

CentOS7安装Flink1.17伪分布式

前提条件 拥有1台CentOS7 CentOS7安装好jdk&#xff0c;官方文档要求java 11&#xff0c;使用java 8也可以。可参考 CentOS7安装jdk8 下载安装包 下载安装包 [hadoopnode1 ~]$ cd installfile/ [hadoopnode1 installfile]$ wget https://archive.apache.org/dist/flink/flin…

Stream流,线程

文章目录 Stream流思想作用三类方法获取方法单列集合(Collection[List,Set双列集合Map(不能直接获取)数组同一类型元素(Stream中的静态方法) 常见的中间方法终结方法收集方法 Optional类 线程相关概念多线程概念实现方式继承Thread类实现Runnable接口比较 常用方法线程安全产生…

【现代控制】倒立摆模型

基础公式 转动惯量&#xff1a; 欧拉拉格朗日等式 倒立摆模型建立 由拉格朗日等式推导出微分方程&#xff1a; 也就是 将zdot移到等式左边&#xff0c;化简得到 展开就是&#xff1a; 系统线性化 法一&#xff1a;雅可比矩阵 法二&#xff1a;小角度假设 化简最终得…