当前位置: 首页 > news >正文

学C的第三十四天【程序环境和预处理】

=========================================================================

相关代码gitee自取

C语言学习日记: 加油努力 (gitee.com)

 =========================================================================

接上期

学C的第三十三天【C语言文件操作】_高高的胖子的博客-CSDN博客

 =========================================================================

                     

1 . 程序的翻译环境和执行环境

                 

ANSI C(C语言标准)任何一种实现中存在两个不同的环境

               

(1). 翻译环境:

            

在这个环境中源代码转换为可执行的机器指令

                  

计算机能够执行二进制指令

但我们平常写的C语言代码文本信息计算机不能直接执行

翻译环境就可以把C语言代码(源代码)翻译为二进制指令(可执行的机器指令

                     


                    

(2). 执行环境:

                  

在这个环境下可以执行二进制的代码(实际执行代码)

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2 . 翻译环境

                        

翻译环境包括 编译链接

编译又包括 预编译(预处理)编译汇编

                

(1). 翻译环境下的 编译 和 链接:

                     

  • 组成一个程序的每个源文件通过编译过程(各自进行编译)分别转换成目标代码(object code)

       

  • 每个目标文件链接器(linker)捆绑在一起形成一个单一而完整可执行程序

            

  • 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库将其需要的函数也链接到程序中

                   

图解:

                     


                    

(2). 编译的几个阶段:

                    

VS这种集成开发环境不方便观察编译各阶段细节

Linux系统下使用gcc编译器更好观察

                

                

(2.1). 预编译(预处理) 阶段

                 

生成文件后缀xxx.i

该阶段进行一些文本操作

                    

       包括

  • 注释删除
  • #include 头文件包含
  • #define 符号替换
  • 所有预处理指令都是在预处理阶段处理

             

图解:

                  

                  

(2.2). 编译阶段

                 

生成文件后缀xxx.s

该阶段把C语言代码翻译为汇编指令

                      

       包括

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号分析

              

图解:

                

                  

(2.3). 汇编阶段

                 

生成文件后缀xxx.o  (object目标文件)

该阶段将编译阶段完成的汇编指令翻译为二进制指令

            

编译阶段进行符号汇总

该阶段则会形成对应的符号表

以便链接时使用

              

图解:

                   


                    

(3). 链接:

             

编译生成的目标文件进行操作

生成可执行程序(也是二进制文件)

                    

       包括

  • 合并段表
  • 符号表(由编译的汇编阶段形成)的合并符号表重定位

              

图解:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                     

3 . 预处理详解

(1). 预定义符号

                  

C语言预定义了一些符号,这些预定义符号都是语言内置的

  • __FILE__             ----          进行编译的源文件
  • __LINE__             ----          文件当前的行号
  • __DATE__             ----          文件被编译的日期
  • __TIME__             ----          文件被编译的时间
  • __STDC__        ----        如果编译器遵循ANSI C(C语言标准),其值为1否则未定义

               

示例:

                     


                    

(2). #define

                   

(2.1). #define 定义标识符

                

写法:

#define name stuff

                   

  • name -- 定义的标识符名称
  • stuff -- 定义的标识符内容

示例:

                      

                      

define定义标识符的时候,最好不要在最后加上“分号 ;”

因为有些编译器可能会把“分号;”也当作stuff(标识符的内容)

示例:

                       

               

(2.2). #define 定义宏

                

写法:

#define name( parament-list ) stuff

                   

  • name -- 定义的宏的名称
  • parament-list -- 参数列表参数会替换放到 stuff 中
  • stuff -- 定义的宏的内容

               

注意:

定义宏时

参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在

参数列表就会被解释为stuff的一部分

         

示例:

                    

注意:

用于对数值表达式进行求值的宏定义都应该用上图这种方式加上括号

对stuff中的各个参数分别加上括号对stuff整体加上括号

避免在使用宏时由于参数中的操作符邻近操作符之间不可预料的相互作用

操作符优先级问题)。

                       

               

(2.3). #define 替换规则

                

程序中扩展#define定义符号和宏时,需要涉及几个步骤

  1. 调用宏时首先对参数进行检查,看看是否包含任何由#define定义的符号
    参数列表中有其它#define定义的符号
    如果是,它们首先被替换
                     
  2. 替换文本随后被插入到程序中原来文本的位置。(参数列表替换stuff中的内容
    对于宏参数名被他们的值所替换
                 
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号
    如果是,就重复上述处理过程

                 

注意:

  • 宏参数#define 定义中可以出现其他#define定义的符号
    但是对于宏不能出现递归。(和函数的区别
  • 预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索

                         

示例:

                     

               

(2.4). # 和 ##

               

### 这两个符号只能在宏里面使用

                      

#:

                  
该符号可以把宏的参数以字符串的形式插入到字符串中

                  

示例:

                

##:

               

##可以把位于它两边的符号合成一个符号

允许宏定义从分离的文本片段创建标识符

             

注意:

这样的连接必须产生一个合法的标识符否则其结果就是未定义的。

         

示例:

                       

               

(2.5). 带副作用的宏参数

                     

宏参数宏的定义中出现超过一次的时候,如果参数带有副作用

那么你在使用这个宏的时候就可能出现危险导致不可预测的后果

副作用就是表达式求值的时候出现的永久性效果

           

示例:

                       

               

(2.6). 宏和函数对比

                

属 性#define定义宏函数

代 码

长 度

每次使用时,宏代码都会被插入到程序中

除了非常小的宏之外程序的长度会大幅度增长

函数代码只出现于一个地方每次使用这个函数时,都调用那个地方的同一份代码

执 行

速 度

更快存在函数的调用和返回额外开 销,所以相对慢一些
操作符 优先级宏参数的求值在所有周围表达式的上下文环境里, 除非加上括号否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括 号函数参数只在函数调用的时候求值一次,它的结果值传递给函数表达式的求值结果更容易预测
带有副 作用的 参数参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果函数参数只在传参的时候求值一 次结果更容易控制

参 数

类 型

宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型函数的参数与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是相同的。
调 试宏是不方便调试函数是可以逐语句调试
递 归宏是不能递归函数是可以递归

                       

               

(2.7). 命名约定

                     

一般来讲,函数和宏的使用语法很相似,所以语言本身没法帮我们区分二者。

所以我们从书写上进行区分

  • 宏名全部大写
  • 函数名不要全部大写

                     


                    

(3). #undef

                

这个指令用于移除一个宏定义移除之后不能再使用

                

写法:

#undef NAMENAME

                   

  • NAME  --  要移除的宏的名字

示例:

                     


                    

(4). 命令行定义

                

许多C的编译器提供了一种能力,允许在命令行中定义符号用于启动编译过程

VS不行gcc可以

             

例如:

当我们根据同一个源文件要编译出一个程序的不同版本的时候,这个特性会有点用处。

(假定某个程序中声明了一个某个长度的数组,如果机器内存有限

我们需要一个很小的数组,但是另外一个机器内存大些,我们需要一个数组能够大些

这时候就可以用命令行定义灵活调整

              

示例:

                     


                    

(5). 条件编译

                 

使用条件编译指令可以决定一条(一组)语句是否进行编译

实现选择性的编译

条件编译指令如果为真,则编译时内容保留

条件编译指令如果为假,则编译时内容删除

           

           

常见的条件编译指令:

                 

指令一:单个分支的条件编译

                                #if  常量表达式                         //一条(一组)语句...                               #endif                                       //常量表达式由预处理器求值。
示例:

                

                

指令二:多个分支的条件编译

                                #if 常量表达式//...#elif 常量表达式//...#else//...#endif
示例:

                

                

指令三:判断是否被定义的条件编译

                                //如果定义过:#if defined(symbol)  //第一种写法#ifdef symbol        //第二种写法//如果未定义过:#if !defined(symbol) //第一种写法#ifndef symbol       //第二种写法//symbol -- 定义的符号
示例:

                

                

指令四:嵌套指令

               

将上面的三种条件编译组合使用

          

示例:

                     


                    

(6). 文件包含

                        

#include指令 可以使另外一个文件被编译

就像它实际出现于 #include指令 的地方一样。

这种替换的方式很简单:

预处理器先删除这条指令,并用包含文件的内容替换

这样一个源文件被包含10次,那就实际被编译10次

                 

                   

头文件被包含的方式:

            

本地文件包含

写法:

#include "filename"

               

查找策略:

先在源文件所在目录下查找,如果该头文件未找到

编译器就像查找库函数头文件一样在标准位置查找头文件

如果找不到就提示编译错误

                 

                   

库文件包含

写法:

#include <filename.h>

               

查找策略:

查找头文件直接去标准路径下去查找

如果找不到就提示编译错误

                 

                   

嵌套文件包含:

                   

如果一个文件有很多头文件

另一个文件包含了该文件,同时该文件也有头文件

再有一个文件包含这两个头文件

那么同一个头文件就有可能重复出现在一个文件中

           

可以使用条件编译来防止头文件重复出现

                                //每个头文件的开头写:#ifndef __TEST_H__#define __TEST_H__//头文件的内容#endif   //__TEST_H__//或者:#pragma once//头文件的内容

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

4 . 运行环境

程序执行的过程:

            

1. 程序必须载入内存中

有操作系统的环境中程序载入内存一般这个由操作系统完成

独立的环境中,程序的载入必须由手工安排

可能是通过可执行代码置入只读内存来完成。

                    

            

2.

程序执行开始,接着便调用main函数

                

            

3. 开始执行程序代码

这个时候程序将使用一个运行时堆栈(stack)(函数栈帧)

存储函数的局部变量返回地址

程序同时也可以使用静态(static)内存

存储于静态内存中的变量在程序的整个执行过程一直保留他们的值

              

            

4. 终止程序

正常终止main函数;也有可能是意外终止

相关文章:

学C的第三十四天【程序环境和预处理】

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十三天【C语言文件操作】_高高的胖子的博客-CSDN博客 1 . 程序的翻译环境和执行环境 在ANSI C(C语言标准)的任何一种实现中&#xff0c;存在两个不同的环境。 &#xff0…...

微服务中间件--Ribbon负载均衡

Ribbon负载均衡 a.Ribbon负载均衡原理b.Ribbon负载均衡策略 (IRule)c.Ribbon的饥饿加载 a.Ribbon负载均衡原理 1.发起请求http://userservice/user/1&#xff0c;Ribbon拦截该请求 2.Ribbon通过EurekaServer拉取userservice 3.EurekaServer返回服务列表给Ribbon做负载均衡 …...

字符设备驱动实例(ADC驱动)

四、ADC驱动 ADC是将模拟信号转换为数字信号的转换器&#xff0c;在 Exynos4412 上有一个ADC&#xff0c;其主要的特性如下。 (1)量程为0~1.8V。 (2)精度有 10bit 和 12bit 可选。 (3)采样时钟最高为5MHz&#xff0c;转换速率最高为1MSPS (4)具有四路模拟输入&#xff0c;同一时…...

python基础5——正则、数据库操作

文章目录 一、数据库编程1.1 connect()函数1.2 命令参数1.3 常用语句 二、正则表达式2.1 匹配方式2.2 字符匹配2.3 数量匹配2.4 边界匹配2.5 分组匹配2.6 贪婪模式&非贪婪模式2.7 标志位 一、数据库编程 可以使用python脚本对数据库进行操作&#xff0c;比如获取数据库数据…...

SpringAOP原理:手写动态代理实现

0、基础知识 AOP我们知道&#xff0c;是在不修改源代码的情况下&#xff0c;为代码添加一些新功能的技术。通过动态代理&#xff0c;可以在不修改原始类代码的前提下&#xff0c;对方法进行拦截和增强。 动态代理常用于在不改变原有业务逻辑的情况下&#xff0c;对方法…...

【旅游度假】Axure酒店在线预订APP原型图 旅游度假子模块原型模板

作品概况 页面数量&#xff1a;共 10 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;旅游度假&#xff0c;生活服务 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「酒店在线预订」的移动端…...

Android JNI系列详解之CMake和ndk-build编译工具介绍

一、前提 CMake和ndk-build只是编译工具&#xff0c;本次主要介绍ndk-build和CMake的区别&#xff0c;下节课介绍他们的使用。 二、CMake工具介绍 CMake&#xff1a;cross platform make&#xff0c;是跨平台的编译工具 CMake是在AndroidStudio2.2之后引入&#xff08;目前默认…...

【Linux取经路】解析环境变量,提升系统控制力

文章目录 一、进程优先级1.1 什么是优先级&#xff1f;1.2 为什么会有优先级&#xff1f;1.3 小结 二、Linux系统中的优先级2.1 查看进程优先级2.2 PRI and NI2.3 修改进程优先级2.4 进程优先级的实现原理2.5 一些名词解释 三、环境变量3.1 基本概念3.2 PATH&#xff1a;Linux系…...

TCP编程流程(补充)

目录 1、listen&#xff1a; 2、listen、tcp三次握手 3、 发送缓冲区和接收缓冲区&#xff1a; 4、tcp编程启用多线程 1、listen&#xff1a; 执行listen会创建一个监听队列 listen(sockfd,5) 2、listen、tcp三次握手 三次握手 3、 发送缓冲区和接收缓冲区&#xff1a;…...

每天一道leetcode:433. 最小基因变化(图论中等广度优先遍历)

今日份题目&#xff1a; 基因序列可以表示为一条由 8 个字符组成的字符串&#xff0c;其中每个字符都是 A、C、G 和 T 之一。 假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如&#xff0c;&quo…...

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…...

去除UI切图边缘上多余的线条

最近接到UI切图&#xff0c;放进项目&#xff0c;显示边缘有多余线条&#xff0c;影响UI美观。开始以为切图没切好&#xff0c;实则不是。如图&#xff1a; ->解决&#xff1a; 将该图片资源WrapMode改为Clamp...

Spring高手之路13——BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor解析

文章目录 1. BeanFactoryPostProcessor 概览1.1 解读 BeanFactoryPostProcessor1.2. 如何使用 BeanFactoryPostProcessor 2. BeanDefinitionRegistryPostProcessor 深入探究2.1 解读 BeanDefinitionRegistryPostProcessor2.2 BeanDefinitionRegistryPostProcessor 的执行时机2.…...

【LeetCode动态规划】详解买卖票I~IV,经典dp题型买

给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…...

【深入探究人工智能】:常见机器学习算法总结

文章目录 1、前言1.1 机器学习算法的两步骤1.2 机器学习算法分类 2、逻辑回归算法2.1 逻辑函数2.2 逻辑回归可以用于多类分类2.3 逻辑回归中的系数 3、线性回归算法3.1 线性回归的假设3.2 确定线性回归模型的拟合优度3.3线性回归中的异常值处理 4、支持向量机&#xff08;SVM&a…...

设计模式之解释器模式详解及实例

1、解释器设计模式概述&#xff1a; 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种设计模式&#xff0c;它主要用于描述如何构建一个解释器以解释特定的语言或表达式。该模式定义了一个文法表示和解释器的类结构&#xff0c;用于解释符合该文法规则的语句。解…...

Nodejs沙箱逃逸--总结

一、沙箱逃逸概念 JavaScript和Nodejs之间有什么区别&#xff1a;JavaScript用在浏览器前端&#xff0c;后来将Chrome中的v8引擎单独拿出来为JavaScript单独开发了一个运行环境&#xff0c;因此JavaScript也可以作为一门后端语言&#xff0c;写在后端&#xff08;服务端&#…...

No115.精选前端面试题,享受每天的挑战和学习

文章目录 变量提升和函数提升的顺序Event Loop封装 FetchAPI&#xff0c;要求超时报错的同时&#xff0c;取消执行的 promise&#xff08;即不继续执行&#xff09;强缓存和协商缓存的区别token可以放在cookie里吗&#xff1f; 变量提升和函数提升的顺序 在JavaScript中&#…...

Elasticsearch:语义搜索 - Semantic Search in python

当 OpenAI 于 2022 年 11 月发布 ChatGPT 时&#xff0c;引发了人们对人工智能和机器学习的新一波兴趣。 尽管必要的技术创新已经出现了近十年&#xff0c;而且基本原理的历史甚至更早&#xff0c;但这种巨大的转变引发了各种发展的“寒武纪大爆炸”&#xff0c;特别是在大型语…...

Flink学习笔记(一)

流处理 批处理应用于有界数据流的处理&#xff0c;流处理则应用于无界数据流的处理。 有界数据流&#xff1a;输入数据有明确的开始和结束。 无界数据流&#xff1a;输入数据没有明确的开始和结束&#xff0c;或者说数据是无限的&#xff0c;数据通常会随着时间变化而更新。 在…...

[Raspberry Pi]如何用VNC遠端控制樹莓派(Ubuntu desktop 23.04)?

之前曾利用VMware探索CentOS&#xff0c;熟悉Linux操作系統的指令和配置運作方式&#xff0c;後來在樹莓派價格飛漲的時期&#xff0c;遇到貴人贈送Raspberry Pi 4 model B / 8GB&#xff0c;這下工具到位了&#xff0c;索性跳過樹莓派官方系統(Raspberry Pi OS)&#xff0c;直…...

17.HPA和rancher

文章目录 HPA部署 metrics-server部署HPA Rancher部署Rancherrancher添加集群仪表盘创建 namespace仪表盘创建 Deployments仪表盘创建 service 总结 HPA HPA&#xff08;Horizontal Pod Autoscaling&#xff09;Pod 水平自动伸缩&#xff0c;Kubernetes 有一个 HPA 的资源&…...

VS2022远程Linux使用cmake开发c++工程配置方法

文章目录 远程连接CMakePresets.json的配置Task.vs.json配置launch.vs.json配置最近使用别人在VS2015上使用visualgdb搭建的linux开发环境,各种不顺手,一会代码不能调转了,一会行号没了,调试的时候断不到正确的位置,取消的断点仍然会进。因此重新摸索了一套使用vs的远程开…...

《强化学习:原理与Python实战》——可曾听闻RLHF

前言&#xff1a; RLHF&#xff08;Reinforcement Learning with Human Feedback&#xff0c;人类反馈强化学习&#xff09;是一种基于强化学习的算法&#xff0c;通过结合人类专家的知识和经验来优化智能体的学习效果。它不仅考虑智能体的行为奖励&#xff0c;还融合了人类专家…...

STM32——RTC实时时钟

文章目录 Unix时间戳UTC/GMT 时间戳转换BKP简介BKP基本结构读写BKP备份寄存器电路设计关键代码 RTC简介RTC框图RTC基本结构硬件电路RTC操作注意事项读写实时时钟电路设计关键代码 Unix时间戳 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日…...

webSocket 开发

1 认识webSocket WebSocket_ohana&#xff01;的博客-CSDN博客 一&#xff0c;什么是websocket WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽…...

c#设计模式-结构型模式 之 代理模式

前言 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时&#xff0c;访问对象不适合或者不能直接 引用目标对象&#xff0c;代理对象作为访问对象和目标对象之间的中介。在学习代理模式的时候&#xff0c;可以去了解一下Aop切面编程AOP切面编程_aop编程…...

openpnp - 自动换刀的设置

文章目录 openpnp - 自动换刀的设置概述笔记采用的openpnp版本自动换刀库的类型选择自动换刀设置前的注意事项先卸掉吸嘴座上所有的吸嘴删掉所有的吸嘴设置自动换刀的视觉识别设置吸嘴座为自动换刀 - 以N1为例备注补充 - 吸嘴轴差个0.3mm, 就有可能怼坏吸嘴END openpnp - 自动换…...

《HeadFirst设计模式(第二版)》第十章代码——状态模式

如下图所示&#xff0c;这是一个糖果机的状态机图&#xff0c;要求使用代码实现&#xff1a; 初始版本&#xff1a; package Chapter10_StatePattern.Origin;/*** Author 竹心* Date 2023/8/19**/public class GumballMachine {final static int SOLD_OUT 0;final static int…...

day-25 代码随想录算法训练营(19)回溯part02

216.组合总和||| 思路&#xff1a;和上题一样&#xff0c;差别在于多了总和&#xff0c;但是数字局限在1-9 17.电话号码的字母组合 思路&#xff1a;先纵向遍历第i位电话号码对于的字符串&#xff0c;再横向递归遍历下一位电话号码 93.复原IP地址 画图分析&#xff1a; 思…...

辽宁省建设工程招标协会网站/广州:推动优化防控措施落地

一些知识点&#xff1a; 要将session进行持久化&#xff1a; 要将cookie进行持久化&#xff0c;则要将cookie中的JSSESSIONID进行持久化。这里要创建一个cookie来覆盖服务器之前自动生成的JSSESSIONID。 这里分为添加进购物车&#xff0c;查看购物车&#xff0c;和前端 前端…...

百度seo和sem/优化营商环境指什么

有两种解决方案&#xff1a; 1. 客户端button一定得是button类型&#xff0c;而不能是submit,且此服务器端的button只能用width0 height0 来隐藏&#xff0c;而不能用style"display:none;" 或visiblefalse来进行隐藏! 2. 在服务器上注册&#xff1a;this.btnStat.At…...

drupal 网站实例/上海百度竞价托管

卡布列克数(Kaprekar number)是具有以下性质的数&#xff1a;对于某个正整数X {\displaystyle X}在n进位下存在正整数 A, B 及 m&#xff0c;且0 < B < b n {\displaystyle 0X 2 A n m B {\displaystyle X^{2}An^{m}B}X A B {\displaystyle XAB}简单的说&#xff0c;…...

兰州市做网站建设的公司/大搜推广

1、先按照cocos2d-x的环境配置要求(ant等)安装好&#xff0c;然后在安卓目录下proj.android新建build.bat&#xff0c;脚本如下&#xff1a;echooffecho准备开始echo设置路径setROOT_PATH"F:\test"setPROJECT_PATH"%ROOT_PATH%\proj.android"setRESOURCES_…...

网站项目报价单模板免费下载/网站建设优化公司

7.集合 注意&#xff1a;列表可以直接生成集合&#xff0c;但不能作为集合的元素&#xff01;&#xff01; &#xff08;1&#xff09;单一集合操作 &#xff08;2&#xff09;集合之间操作...

郴州市地图/百度搜索关键词优化

近年来&#xff0c;越来越多的人加入了测试大军中&#xff0c;很多人也想通过自学来学习软件测试技术加入这个行业&#xff0c;但是现在软件测试的书籍越来越多&#xff0c;也良莠不齐&#xff0c;而且软件测试涉及的技术也越来越多。鉴于此情况&#xff0c;为了回馈大家&#…...