欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    Linux下的C编程.ppt

    • 资源ID:6511159       资源大小:733KB        全文页数:79页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Linux下的C编程.ppt

    第三章 Linux下的C编程基础,本章目标:,熟悉Linux系统下的开发环境熟悉Vi的基本操作熟练Emacs的基本操作熟悉Gcc编译器的基本原理熟练使用Gcc编译器的常用选项熟练使用Gdb调试技术熟悉Makefile基本原理及语法规范,Linux下C语言编程概述,C语言的特点:C语言是“中级语言”,它把高级语言的基本结构和语句与低级语言的实用性结合起来。C语言像汇编一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。C语言是结构化的语言。C语言采用代码与数据分离,使程序的各个部分除了必要的信息交流外彼此独立。,C语言的特点:,C语言功能齐全。C语言具有各种各样的数据类型,并引入了指针概念,可使程序效率更高。C语言可移植性强。C语言适合多种操作系统,如DOS,Windows,Linux;也适合多种体系结构,尤其适合在嵌入式领域的开发。,char*f()char a5;char b5;a0=a;a1=b;a2=c;a3=d;a4=e;strcpy(b,a);return b;请问:一:该函数中用a作为一个字符串是否存在问题?二、该函数返回的b是否可用,为什么?,x value is 0 x12345566xAddress is 0 x12ff7c,#include int main(int argc,char*argv)unsigned int x=12345566;printf(x value is 0 x%dn,x);printf(xAddress is 0 x%xn,x value is 0 x123456xAddress is 0 x12ff7cxsize is 4,#include stdio.h“int main(int argc,char*argv)unsigned int x=123456;printf(x value is 0 x%dn,x);printf(xAddress is 0 x%xn,Linux下C语言编程环境概述,(1)编辑器:Linux下的编辑器就如Windows下的word、记事本一样,完成对所录入文字的编辑功能。Linux最常用的编辑器有Vi(Vim)和Emacs。(2)编译连接器 编译是指源代码转化成可执行代码的过程,它所完成的工作如下图所示:,编译过程非常复杂,包括词义、语法和语义的分析,中间代码的生成和优化,符号表的管理和出错处理等。在Linux中最常用的编译器是Gcc编译器。arm-none-linux-gnueabi-gccarm-2007q3-51-arm-none-linux-gnueabi-i686.tar.bz 命令:tar xvjf arm-2007q3-51-arm-none-linux-gnueabi-i686.tar.bz-C/usr/local/arm,Linux下C语言编程环境概述,(3)调试器 调试器不是代码执行必备工具,而是专门为程序员方便调试程序而用的。在编程过程中,往往调试所消耗的时间远远大于编写代码的时间。Gdb是绝大多数Linux开发人员所使用的调试器。(4)项目管理器Linux中的项目管理器“make”有些类似于Windows中Visual C+里的“工程”,它是一种控制编译或者重复编译软件的工具。,Linux下C语言编程环境概述,Vi编辑器,Linux系统提供了一个完整的编译器家族系列:Ed,Ex,Vi和Emacs等;按功能它们可以分为两大类:行编辑器(Ed,Ex)和全屏编辑器(Vi,Emacs)。行编辑器每次只能对一行进行操作。全屏编辑器可以对整个屏幕进行编辑,用户编辑的文件直接显示在屏幕上。,Vi有3种模式,分别为命令行模式、插入模式及底行模式。(1)命令行模式用户在用Vi编辑文件时,最初进入的为一般模式。在该模式中可以通过上下移动光标进行“删除字符”或“整行删除”等操作。(2)插入模式只有在该模式下,用户才能进行文字编辑输入,用户可按Esc键回到命令行模式。,Vi的模式,Vi的模式,(3)底行模式在该模式下,光标位于屏幕的底行。用户可以进行文件保存或退出操作,也可以设置编辑环境,如寻找字符串,列出行号等。,Vi的基本流程,(1)进入Vi,即在命令行键入 Vi hello.c(文件名),此时进入的是命令行模式,光标位于屏幕的上方。(2)在命令行模式下键入i进入到插入模式,可以看到屏幕底部显示有“插入”表示插入模式,在该模式下可以输入文字信息。(3)在插入模式中,输入“Esc”,则当前模式转入命令行模式,并在底行行中输入“:wq”(存盘退出)进入底行模式。,(1)命令行模式的常见功能键。,(2)插入模式的功能键只有一个,即Esc退出到命令行模式。,(2)插入模式的功能键只有一个,即Esc退出到命令行模式。,(3)底行模式的功能键。,(3)底行模式的功能键。,Emacs,Emacs是一款功能强大的编译器,融合了编辑,编译和调试功能。Emacs只有一种模式,即编辑模式,它的命令全靠功能键完成。,注释:C-表示按住Ctrl键的同时键入字符,因此,C-f就表示按住Ctrl键同时键入f。M-表示当键入字符时同时按住Alt键。,Emacs的基本操作,启动Emacs在命令行键入“Emacs文件名”,若文件名缺省,可以在emacs编辑文件后另存时指定。也可以从“编程”emacs”打开。接着可单击任意键进入Emacs的工作窗口。,进入Emacs后,即可进行文件编辑。Emacs光标移动功能键,进入Emacs,Emacs剪切和粘贴,Emacs复制文本,Emacs复制文本包括两步:选择复制区域和粘贴文本选择复制区域的方法:首先在复制起始点(A)按下“C-space”或“C-”使它成为一个表示点,再将光标移至复制结束点(B),再按下“M-w”,就可将A与B之间的文本复制到系统的缓冲区中。再使用功能键C-y将其粘贴到指定位置。,Emacs查找文本,Emacs保存文档,在Emacs中保存文档的功能键为“C-x C-s”,这是在屏幕底下回出现“Wrote/root/workplace/editor/why”字样。Emacs有自动保存机制,自动保存的文件名前后都有一个“#”,例如编辑名为“hello.c”的文件,自动保存后为“#hello.c#”.,Emacs退出文档,退出文档的功能键为“C-x C-c”。,Emacs中的模式,这里所说的模式,是Emacs中的各种辅助环境。Emacs会判断文件的类型,自动选择相应的模式。也可以手动选择各种模式,用功能键“M-x”,然后输入模式的名称。如在C模式下,用户拥有“自动缩进”注释”,“预处理扩展”等功能。在Emacs中用”M-”可以产生一条右缩进的注释。,Gcc编译器,一般来说,系统安装后就已经安装和设定好了gcc。在shell的提示符下键入gcc v,屏幕上就会显示出目前正在使用的gcc的版本,同时这可以确定系统所支持的是ELF还是a.out可执行文件格式,gcc的使用,gcc的使用格式如下:$gcc optionsfilenames其中filenames为所要编译的程序源文件。当使用gcc时,gcc会完成预处理、编译、汇编和连接。前三步分别生成目标文件,连接时,把生成的目标文件链接成可执行文件。gcc可以针对支持不同的源程序文件进行不同处理,文件格式以文件的后缀来识别。,Gcc所支持后缀名解释,Gcc编译流程,Gcc编译流程解析预处理(Pre-Processing)编译(Compiling)汇编(Assembling)链接(Linking),例如对于hello.c源代码如下:#includeint main()printf(“hello!This is our embedded world!n”);return 0;,Gcc编译流程,(1)预处理阶段Gcc指令的一般格式:Gcc选项要编译的文件选项目标文件rootlocalhost Gcc#Gcc E hello.c o hello.i“-o”指目标文件“.i”文件为已经过预处理的C原始程序“-E”只进行预编译,不做其它处理这一步编译器将stdio.h编译进来。,Gcc编译流程,Gcc编译流程,(2)编译阶段Gcc首先要检查代码的规范性、是否有语法错误等,在检查无误后,Gcc把代码编译成汇编语言。rootloaclhost Gcc#Gcc S hello.i o hello.s,此选项只进行编译而不进行汇编,生成汇编代码。,Gcc编译流程,(3)汇编阶段汇编阶段把编译阶段生成的“.s”文件转成目标文件rootloaclhost Gcc#Gcc c hello.s o hello.o,Gcc编译流程,(4)链接阶段在成功编译后,进入了链接阶段。rootloaclhost Gcc#Gcc hello.o o helloGcc生成可执行文件;rootloaclhost Gcc#./hellohello!This is our embedded world!,Gcc的告警和出错选项,Gdb调试器,Linux系统中包含了GNU 调试程序gdb,它是一个用来调试C和 C+程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。gdb 所提供的一些功能如下所示:运行程序,设置所有的能影响程序运行的参数和环境;控制程序在指定的条件下停止运行;,当程序停止时,可以检查程序的状态;修改程序的错误,并重新运行程序;动态监视程序中变量的值;可以单步执行代码,观察程序的运行状态。,Gdb调试器,gdb程序调试的对象是可执行文件,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用gdb调试。如果要让产生的可执行文件可以用来调试,需在执行gcc指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb 利用这些信息使源代码和机器码相关联。,Gdb调试器,gdb基本命令 还可以用下面的方式来运行gdb:gdb filename其中,filename是要调试的可执行文件。用这种方式运行gdb可以直接指定想要调试的程序。这和启动gdb后执行file filename命令效果完全一样。也可以用gdb去检查一个因程序异常终止而产生的core文件,或者与一个正在运行的程序相连。gdb支持很多的命令且能实现不同的功能。这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令,下面列出了在使用gdb 调试时会用到的一些命令。,1)file命令:装入想要调试的可执行文件。2)cd命令:改变工作目录。3)pwd命令:返回当前工作日录。4)run命令:执行当前被调试的程序。5)kill命令:停止正在调试的应用程序。6)list命令:列出正在调试的应用程序的源代码。7)break命令:设置断点。,8)Tbreak命令;设置临时断点。它的语法与break相同。区别在于用tbreak设置的断点执行一次之后立即消失。9)watch命令:设置监视点,监视表达式的变化。10)awatch命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同。11)rwatch命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同。12)next命令:执行下一条源代码,但是不进入函数内部。也就是说,将一条函数调用作为一条语句执行。执行这个命令的前提是已经run,开始了代码的执行。,13)step命令:执行下一条源代码,进入函数内部。如果调用了某个函数,会跳到函数所在的代码中等候一步步执行。执行这个命令的前提是已经用run开始执行代码。14)display命令:在应用程序每次停止运行时显示表达式的值。15)info break命令:显示当前断点列表,包括每个断点到达的次数。16)info files命令:显示调试文件的信息。17)info func命令:显示所有的函数名。18)info local命令:显示当前函数的所有局部变量的信息。,19)info prog命令:显示调试程序的执行状态。20)print命令;显示表达式的值。21)delete命令:删除断点。指定一个断点号码,则删除指定断点。不指定参数则删除所有的断点。22)Shell命令:执行Linux Shell命令。23)make命令:不退出gdb而重新编译生成可执行文件。24)Quit命令:退出gdb。,Gdb调试举例,rootlocalhost Gdb#gcc g hello.c o hello注意:Gdb进行调试的是可执行文件,而不是如“.c”的源代码,因此要通过Gcc编译生成可执行文件才能用Gdb调试。rootlocalhost Gdb#gdb hello这里在Gdb的启动画面中指出了Gdb的版本号、使用的库文件信息;接下来进入了由“(gdb)”开头的命令行界面了。,(Gdb)l在Gdb中键入“l”就可以查看所载入的文件了。“l”-list“b”-breakpoint“help”查看帮助信息(Gdb)b 6 代码运行到第5行之前暂停,Gdb调试举例,(Gdb)info b在设置完断点之后,键入“info b”查看设置断点情况,在Gdb中可以设置多个断点(Gdb)rGdb默认从首行开始运行代码,可键入“r”(Gdb)n 单步执行 不进入函数(Gdb)s 单步执行 进入函数(Gdb)c 恢复程序的正常运行,Gdb调试举例,Makefile基本结构,GNU make的主要功能是读进一个文本文件makefile并根据makefile的内容执行一系列的工作。makefile的默认文件名为GNUmakefile、makefile或Makefile,当然也可以在make的命令行中指定别的文件名。如果不特别指定,make命令在执行时将按顺序查找默认的makefile文件。多数Linux程序员使用第三种文件名Makefile。因为第一个字母是大写,通常被列在一个目录的文件列表的最前面。,Makefile基本结构,Makefile是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件。这些规则主要是描述哪些文件(称为target目标文件,不要和编译时产生的目标文件相混淆)是从哪些别的文件(称为dependency依赖文件)中产生的,以及用什么命令(command)来执行这个过程。,Makefile基本结构,依靠这些信息,make会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间(称为该文件时间戳)至少比它的一个依赖文件还旧的话,make就执行相应的命令,以更新目标文件。目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。,Makefile基本结构,一个Makefile文件主要含有一系列的规则,每条规则包含以下内容。一个目标(target),即make最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“clean”。一个或多个依赖文件(dependency)列表,通常是编译目标文件所需要的其他文件。一系列命令(command),是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为TAB字符。,例如,有以下的Makefile文件:#一个简单的Makefile的例子#以#开头的为注释行test:prog.o code.ogcc o test prog.o code.oprog.o:prog.c prog.h code.hgcc c prog.c o prog.ocode.o:code.c code.hgcc c code.c o code.oclean:rm f*.o,Makefile基本结构,上面的Makefile文件中共定义了四个目标:test、prog.o、code.o和clean。目标从每行的最左边开始写,后面跟一个冒号(:),如果有与这个目标有依赖性的其他目标或文件,把它们列在冒号后面,并以空格隔开。然后另起一行开始写实现这个目标的一组命令。在Makefile中,可使用续行号()将一个单独的命令行延续成几行。但要注意在续行号()后面不能跟任何字符(包括空格和键)。,一般情况下,调用make命令可输入:#make targettarget是Makefile文件中定义的目标之一,如果省略target,make就将生成Makefile文件中定义的第一个目标。对于上面Makefile的例子,单独的一个“make”命令等价于:#make test 因为test是Makefile文件中定义的第一个目标,make首先将其读入,然后从第一行开始执行,把第一个目标test作为它的最终目标,所有后面的目标的更新都会影响到test的更新。第一条规则说明只要文件test的时间戳比文件prog.o或code.o中的任何一个旧,下一行的编译命令将会被执行。,Makefile基本结构,但是,在检查文件prog.o和code.o的时间戳之前,make会在下面的行中寻找以prog.o和code.o为目标的规则,在第三行中找到了关于prog.o的规则,该文件的依赖文件是prog.c、prog.h和code.h。同样,make会在后面的规则行中继续查找这些依赖文件的规则,如果找不到,则开始检查这些依赖文件的时间戳,如果这些文件中任何一个的时间戳比prog.o的新,make将执行“gcc c prog.c o prog.o”命令,更新prog.o文件。,Makefile基本结构,以同样的方法,接下来对文件code.o做类似的检查,依赖文件是code.c和code.h。当make执行完所有这些套嵌的规则后,make将处理最顶层的test规则。如果关于prog.o和code.o的两个规则中的任何一个被执行,至少其中一个.o目标文件就会比test新,那么就要执行test规则中的命令,因此make去执行gcc命令将prog.o和code.o连接成目标文件test。在上面Makefile的例子中,还定义了一个目标clean,它是Makefile中常用的一种专用目标,即删除所有的目标模块。,Makefile基本结构,现在来看一下make做的工作:首先make按顺序读取makefile中的规则,然后检查该规则中的依赖文件与目标文件的时间戳哪个更新,如果目标文件的时间戳比依赖文件还早,就按规则中定义的命令更新目标文件。如果该规则中的依赖文件又是其他规则中的目标文件,那么依照规则链不断执行这个过程,直到Makefile文件的结束,至少可以找到一个不是规则生成的最终依赖文件,获得此文件的时间戳,然后从下到上依照规则链执行目标文件的时间戳比此文件时间戳旧的规则,直到最顶层的规则,Makefile基本结构,通过以上的分析过程,可以看到make的优点,因为.o目标文件依赖.c源文件,源码文件里一个简单改变都会造成那个文件被重新编译,并根据规则链依次由下到上执行编译过程,直到最终的可执行文件被重新连接。例如,当改变一个头文件的时候,由于所有的依赖关系都在Makefile里,因此不再需要记住依赖此头文件的所有源码文件,make可以自动的重新编译所有那些因依赖这个头文件而改变了的源码文件,如果需要,再进行重新连接。,实例,编译器的安装举例 将交叉编译器拷贝到/usr/local子目录启动虚拟机、运行Linux后,查找并选择交叉编译器,选择复制菜单条,如图3.1所示。,然后在Linux图形桌面环境,在/usr/local子目录,点击鼠标右键,选择“粘贴1个URL”,交叉编译器将会粘贴到该子目录,如图3.2所示。,建立/usr/local/arm子目录并解压缩交叉编译器在Linux终端窗口输入如下命令,将建立/usr/local/arm子目录,然后将交叉编译器解压缩到该子目录下。要求启动Linux时,以root用户名登录。rootlocalhost local#mkdir/usr/local/arm rootlocalhost local#tar xvjf arm-2007q3-51-arm-none-linux-gnueabi-i686.tar.bz-C/usr/local/arm,解压缩后的代码分6个子目录保存,可以用如下命令查看。rootlocalhost local#cd/usr/local/armrootlocalhost arm#ls-l总计 8drwxr-xr-x 8 root root 4096 12-25 10:30 arm-2007q3rootlocalhost arm#rootlocalhost arm#cd arm-2007q3rootlocalhost arm-2007q3#ls-l总计 48,drwxrwxr-x 6 root root 4096 2007-09-28 arm-none-linux-gnueabidrwxr-xr-x 2 root root 4096 2007-09-28 bindrwxrwxr-x 2 root root 4096 2007-09-28 includedrwxrwxr-x 3 root root 4096 2007-09-28 libdrwxrwxr-x 4 root root 4096 2007-09-28 libexecdrwxrwxr-x 3 root root 4096 2007-09-28 share,4 对查找工具链的路径变量进行修改 安装了交叉编译器后,需要修改/root/.bashrc文件内容,应该在这个文件中增加一行语句,指出交叉编译器所在的路径。之后每当打开终端窗口时,Linux自动运行/root/.bashrc文件,给出缺省路径名的交叉编译器的查找路径。,(1)在/root/.bashrc文件中增加语句可以用如下命令检查原来的路径变量值:rootlocalhost local#echo$PATH/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin,然后用vi增加一行语句:rootlocalhost local#vi/root/.bashrcexport PATH=/usr/local/arm/arm2007q3/bin:$PATH,(2)重启/root/.bashrc文件可以使用source命令重启/root/.bashrc文件,然后系统才能修改查找路径:rootlocalhost#source/root/.bashrc如果不使用source命令重启文件,也可以用exit命令关闭终端窗口,然后再次打开终端窗口,打开终端窗口过程中系统会自动启动/root/.bashrc文件。,(3)检查新的路径变量值用echo命令可以检查新的路径变量值:rootlocalhost#echo$PATH/usr/local/arm/arm-2007q3/bin:/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin,输入、编译、运行一个程序全过程举例,假定要在主机/home/nfs1目录下,建立一个子目录hello,在该子目录下建立一个hello.c文件、建立一个Makefile文件,然后在主机编译hello.c文件,产生可执行文件hello,在目标板执行该文件,执行这些操作的全过程及相关文件的内容如下所示。,下述操作中,在主机Linux终端窗口输入minicom后,这个窗口成为目标板终端窗口,然后挂接NFS;操作中,命令是在目标板终端窗口输入的;其余操作、均在主机Linux终端窗口进行;而和表示要输入的文件的内容。,建立hello目录,进入hello目录rootlocalhost nfs1#mkdir/home/nfs1/hellorootlocalhost nfs1#cd/home/nfs1/hello 用vi编辑程序建立hello.c源文件rootlocalhost hello#vi hello.c,hello.c文件内容为#include#include int main(int argc,char*argv)printf(Hello Reader,Congradulations!n);return(0);,建立Makefile文件rootlocalhost hello#vi Makefile Makefile文件内容为CC=/usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gccall:$(CC)-o hello hello.cclean:-rm-f*.o hello,输入上述代码后,保存文件并退出。上述Makefile文件内容中:CC 表示主编译器 all:表示主入口 clean:表示清除以前编译产生的结果另外,语句“$(CC)-o hello hello.c”和“-rm-f*.o hello”,前面有一个制表符Tab,不是空格。,在目标板终端窗口挂接NFS如果没有挂接NFS,则需要挂接。#mount-o soft,nolock,rsize=1024-v 192.168.1.5:/home/nfs1/tmp,在主机终端窗口对hello.c文件进行编译rootlocalhost hello#make cleanrm-f*.o hellorootlocalhost hello#make/usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gcc-o hello hello.c,在目标板终端窗口运行hello程序文件并且显示输出结果rootTechv_OMAP35xx:/var/volatile/tmp#cd/tmp/hellorootTechv_OMAP35xx:/var/volatile/tmp/hello#./helloHello Reader,Congradulations!,上述内容中./hello,表示从当前目录装入并运行hello可执行文件。由于通过NFS挂接,目标板/tmp目录挂接到主机/home/nfs1目录,在目标板输入./hello并回车后,目标板Linux内核通过网口,把主机/home/nfs1/hello目录下的hello可执行文件,装入到目标板的内存并运行,执行结果显示在目标板的终端窗口。,

    注意事项

    本文(Linux下的C编程.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开