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

C++ | 对比inline内联函数和宏的不同点

在这里插入图片描述

在这里插入图片描述

文章目录

  • 一、前言
  • 二、宏的优缺点分析
    • 1、概念回顾
    • 2、宏的缺点
    • 3、宏的优点
  • 三、inline内联函数
    • 1、概念
    • 2、特性①:空间换时间
    • 🎁趣味杂谈:庞大的游戏更新包
    • 3、特性②:inline实现机制
    • 4、特性③:inline的声明与定义
      • 反汇编观察函数调用的流程
      • 内联函数的生成机制【⭐】
  • 四、总结与提炼

一、前言

本文我们聊一聊一下宏和内联函数之间的关系。

  • 在预处理章节,我们重点介绍了什么是宏,以及宏和函数之间的区别,还记得下面这张图吗,我们对宏和函数之间做了一个很细致的分析🔍
  • 那在本文中,我们来说的就不是普通的函数了,它叫做【内联函数】,是C++里面独有的,由inline关键字进行修饰,具体怎样,敬请看下去吧👇

在这里插入图片描述

二、宏的优缺点分析

在将内联函数之间前,我们再来聊聊有关宏的一些内容

1、概念回顾

下面是宏的申明方式:

#define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中

注:① 参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

  • 在学习了C语言后,如果我不带你去回顾这一些,那你是否能立马写出一个宏来呢,例如:写一个用于求和的宏函数
  • 那我相信对于很多同学来说都会措手不及,答案会像是下面这样千奇百怪🤣
//1.
#define Add(int x, int y)	return x + y;
//2.
#define ADD(x, y) x + y
//3.
#define ADD(x, y) (x + y)
//4.
#define ADD(x, y) ((x) + (y));
//5.
#define ADD(x, y) ((x) + (y))
  • 那究竟哪一个对的呢?首先第一个肯定是错误的,因为我说了这是【宏】,而不是函数,这样子是函数的写法。

后面四个的主要区别就在于后面的stuff,我们一一来分析一下

  • 首先若是写成下面这样,传入1给到x,传入2给到y,此时去我们去Linux环境下看看预处理之后会发生什么
int ret = ADD(1, 2);
  • 可以看到很明显进行了一个【宏替换】

在这里插入图片描述

  • 若此时我将调用的函数后面再乘上一个3呢,这会发生什么?
int ret = ADD(1, 2) * 3;
  • 可以观察到此时在预处理阶段也是直接进行了一个替换,不过仔细观察就可以发现,由于*的优先级来得高,所以2会和后面的3先进行一个运算,这也就造成了最后结果的不同

在这里插入图片描述


所以我们应该要像下面这样,在外层加上一个大括号,防止出现优先级的问题

#define ADD(x, y) (x + y)
  • 可是这样真的就可以了吗?若此时我向ADD宏函数传入下面这样的参数呢?会发生什么?
int a = 10;  
int b = 20;
int ret = ADD(a | b, a & b);
  • 编译器还是一样会去做傻傻的替换,但是这个时候我们又得注意优先级的问题了,对于+号来说,它的优先级高于&按位与和|按位或的,如果不清楚优先的话可以看看操作符汇总大全
  • 所以中间的【b】和【a】会先进行结合,然后再去算&|

在这里插入图片描述

  • 如果要防止这种表达式的传入而造成的优先级问题,可以对内部的形参也加上一个括号(),这样就不会出现问题了

#define ADD(x, y) ((x) + (y));
  • 可是呢,有的同学虽然想到了这一点,但是却在最后面加了一个;号,对于分号来说是我们在写代码的时候作为一条语句结束的标志,但是对于宏来说也可以写分号吗?
  • 将原先的传参继续替换成下面这样来试试
int ret = ADD(1, 2) * 3;
  • 继续通过预处理之后的结果去进行观察,就可以发现在进行宏替换之后原先的语句中出现了;号,但是分号后面还有3要乘,这个时候其实就不对了,所以宏定义后是不可以加分号的

在这里插入图片描述

  • 最后这一种才是最正确的写法
#define ADD(x, y) ((x) + (y))		//✔

2、宏的缺点

看了上面有关【宏】概念的一些回顾,我们来聊聊它的缺点所在

① 宏可能会带来运算符优先级的问题,导致程容易出现错。【加括号太麻烦了!!!】

  • 这一点相信你在看了上一小节的叙述之后一定是感同身受,只是完成一个两数相加的功能,就需要加上这么多括号了,若是再复杂一些的功能,那岂不是要加很多了🙄

② 宏是不能调试的【这点比较致命👈】

  • 可以观察到,无论是在哪个平台下,对于宏来说都是无法调试的

Windows环境下VS

在这里插入图片描述

Linux环境下gdb

在这里插入图片描述

③ 没有类型安全的检查【直接替换】

  • 可以看到,无论我传入何种类型的参数,都不会出现问题。这点其实说明了宏对于类型的检查是不严谨的

在这里插入图片描述

④ 有些场景下非常复杂,容易出错,不容易掌握

  • 之前我有写过一篇文章叫做使用宏将一个整数的二进制位的奇数位和偶数位交换。为了实现这个功能我写了一个这样的宏函数
#define SWAP(n) num = (((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1))
  • 乍眼一看,就感觉非常复杂,都是一些二进制的位运算,若是没有对这一块很熟悉的话,就很容易写错,因此说对于一个宏来说其实要实现一些功能的时候会非常繁琐

3、宏的优点

了解了宏的缺点之后,我们再来瞧瞧它的优点,既然在一些场景被广泛使用,那一定也具有它的优点💡

宏常量提高复用性和可维护性

  • 这一点很好理解,也就是我们平常用得最多的,一般会将频繁使用到的一些数字定义成一个宏,这样就不需要每次写数字了,直接写这个宏所定义的变量即可
  • 而且在修改的时候也会很方便,只需要修改一下宏定义处即可,实现一改多改【这一点在项目里面还是比较常用的
#define n 500

宏函数类型不固定,int、double、float都可以用

  • 这一点其实我们在讲缺点的时候也有提及,虽然类型检查得不严谨,但真正用起来还是很香的,这很像是我们之前说到过的函数重载,虽然函数名相同,但是可以传入不同的参数实现不同的运算

宏函数不用建立栈帧,因此不会产生消耗

  • 刚才我们有观察过,对于【宏】来说是不能调试的,因为它根本就不是一个真正意义上的函数,只是具备函数的功能罢了。既然不是函数的话也就不会在栈上建立函数栈帧,那也就不会有过多的消耗

好,以上就是本文所要讲的有关【宏】相关的所有内容,希望能唤起读者对这个知识点的回忆

三、inline内联函数

接下去我们就正式来讲讲C++中的独有的【内联函数】

1、概念

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率

  • C++的祖师爷呢,认为【宏】存在一定的缺陷,但是呢也有它的好处,也就是直接做替换,不需要开辟函数栈帧,所以在C++中就出现了内敛函数这么一个东西
inline int Add(int x, int y)
{int z = x + y;return z;
}
  • 但是它真不会去进行函数调用吗?我们到VS中来看看

在这里插入图片描述

  • 那此时就又同学疑惑了🤨这不还是会有call指令吗,哪来的不调用一说呢?
  • 因为我们还需要去做一些配置💻

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 然后我们再去观察一下汇编就可以发现不存在call指令了,编译器直接将内敛函数Add做了展开

在这里插入图片描述

  • 所以C++中我们是不推荐用宏的,因为有内联函数这个特性,即保留了宏的优点,无需调用函数建立栈帧,而且还修复了宏的缺陷,不再需要将内容写得那么复杂,写成日常的函数形式即可,只需要在前面加上一个inline关键字,就可以起到这种效果。非但如此,它还可以调试💻

接下去我们再来介绍一下有关内敛函数的一些特性

2、特性①:空间换时间

有同学可能不是很理解空间换时间是什么意思,可以看看时空复杂度章节。不过要说明的一点是这里的空间不是内存,是编译后的程序,而【空间换时间】就会使得编译出来的可执行程序会变大

  • 对于这种空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用
    • 【缺陷】:可能会使目标文件变大;
    • 【优势】:少了调用开销,提高程序运行效率;
  • 可以通过下面这幅图来看看:此时程序中有一个swap()函数,内部有10行代码。在程序的1000个地方都会对其进行调用,那请问此时去使用内联函数和不使用内联函数的区别是什么?
    • 当不使用内联函数时,就是将这个swap()函数当做普通的函数的话,我们知道在底层会进行一个call指令再通过jump指令跳转到这个函数所在地址然后执行这个函数,那每一个调用的地方都要跳转的话,就会跳转1000次,所以swap + 调用swap指令,合计是1000 + 10条指令
    • 当使用内联函数时,通过上面的学习可以知道,它不会去进行一个函数的调用,而是直接将相关的指令拷贝到程序中调用这个swap()函数的每一块地方,所以swap + 调用swap指令,合计是1000 * 10条指令

在这里插入图片描述

  • 可以看出,在使用内联函数减少函数调用的同时也会增加程序的负担,使得目标文件会变得很大

🎁趣味杂谈:庞大的游戏更新包

在理解了一个函数设不设置内联函数的区别的时候,顺带来谈一谈这个目标文件体积变大的缘故

  • 要知道,干我们这一行基本一年到头都是在公司,也有逢年过节才能回家一趟,而且平常工作忙得也没有时间玩游戏,那此刻当你过年回家的时候,就看到家里的一些弟弟妹妹拿着手机📱在打《王者荣耀》,这相信是最正常不过了
  • 那此时呢,你也心里痒痒,打开了你尘封已久的王者荣耀,然后看到要更新,而且一看就是4、5个G,突然之间就不想玩了😅更新的过程中只能眼巴巴地看着别人玩,
  • 不过呢,你有个同事,也是很久都没有玩过游戏了,也是一样进去更新,但是呢她却3、5分钟更新好了,因为更新包只有3、500M。这是为什么呢?原来她是苹果手机,系统是IOS系统,其实对于更新的这些内容都是指令,只是你们的指令数目不同而已。那我们都知道【苹果】这家公司系统是自己设计的,而且对于像芯片、硬件、软件各方面都领先于同行
  • 所以说这个性能不一样就会手机系统上使用的软件也存在差异。别人这个性能好,在优化各种方面都齐全,所以就不会导致这个更新包越变越大,相反对比我们平常使用的几千元的安卓手机,却越用越卡,这也是很多人选择使用苹果手机的原因👈

在这里插入图片描述

3、特性②:inline实现机制

好,小插曲,我们回归正题,继续来讲讲内联函数的第二大特性 —— 【inline实现机制】

  • inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同
  • 一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

《C++prime》第五版关于inline的建议:

在这里插入图片描述
我们可以到VS中来观察一下

  • 可以观察到当内联函数的内容增多时,程序中去调用这个内联函数依旧会执行call指令,而不是将其函数中的内容直接拷贝到程序调用处,即使是加了这个inline关键字,似乎还是起不到内联函数的作用,这是为什么呢?
  • 因为编译器在对于这个内联请求的时候发觉不对劲,所以选择忽略了这个请求,而不是像宏那样无论怎样都会傻傻地进行替换

在这里插入图片描述

  • 这其实就是内联函数在替代宏之后很优秀的一个特性,假设说现在你这个设置的内联函数有1000多行代码,在一个大项目中又有1000个地方调用了这个内联函数。
    • 如果不采用将其展开去调用的话消耗的顶多也就是1000 + 1000条指令
    • 如果采用内联将其展开的话消耗的就是1000 * 1000条指令,这就很恐怖了😱
  • 那上面这个还是个普通的大一点的函数,但你再想如果是**··**呢?层层地往下调用再一层层地返回来,那需要调用的指令就更多了,如果全部站开的话,就会造成一个灾难性的后果⚠

在这里插入图片描述

所以呢,加不加内敛是你的事,最终要不要把它真的展开变成内敛编译器说了算,所以我们在使用的时候一般是比较短小、调用频繁的函数(10几行以内)加上内联,其他就不加了

4、特性③:inline的声明与定义

inline内联函数的第三个特性,就是我们要注意内联函数的定义和声明不可以分开,导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

// F.h
#include <iostream>
using namespace std;inline void f(int i);
//--------------------------
// F.cpp
#include "F.h"void f(int i)
{cout << i << endl;
}
//--------------------------
// main.cpp
#include "F.h"int main()
{f(10);return 0;
}
  • 通过去VS中执行这段分文件代码,可以发现它不是一个【编译时错误】,而是一个【运行时错误

在这里插入图片描述
👉 这种错误一般都是最后链接目标文件的时候除了问题,不是很清楚的可以看看程序的编译和链接
👉 对于这些很复杂的符号func@@YAXH@Z,是C++中的函数名修饰,可以看看探究函数重载的原理:函数名修饰

在这里插入图片描述
那我们现在就要去思考,为什么会出现这种【运行时错误】呢?

  • 最主要的一点首先你要知道:内联函数的不进符号表的,因为对于内联函数来说它在其调用的地方都展开了,所以不需要产生一串指令把它放到符号表中,再通过一条一条指令去调用

反汇编观察函数调用的流程

对于内联函数来说是这样,但是普通函数来说是怎么一步步地进行调用的呢?我们可以通过汇编来看看💻

  • 对于函数的地址来说,在指针章节我们有说过,它值得就是【函数指针】,但是从汇编角度来看,它call的到底是谁的地址呢?

在这里插入图片描述

  • 通过按下F11跳转到了一条叫做【jmp】的指令,此时你去观察这个地址,其实就是这条【jmp】的地址,在英语中jump是跳的意思,那你可以将这条指令理解为一个中转站,call指令会暂时跳到这条指令所在的地址,然后再通过这条指令去找需要调用函数的地址

在这里插入图片描述

  • 此刻,再按下F10的话就会通过这个函数的地址找到这个函数,此时就开始执行函数内部的逻辑,

在这里插入图片描述

  • 然后,当执行完函数内部的逻辑后,便回到了call指令的下一条指令,这就算是一次函数调用的过程

在这里插入图片描述

可以将它们放到一起来观察,就可以发现它们之间的逻辑非常紧密

在这里插入图片描述
如果对上面过程还是不太理解的可以看看反汇编深挖【函数栈帧】的创建和销毁

内联函数的生成机制【⭐】

上面是对于普通函数的调用机制,那对于内联函数呢?也是这么去跳转吗?

  • 一定要注意!内联内联,那么这个函数的内容就直接放到调用的地方
  • 它便说:也就是我不需要你再通过这么繁琐的步骤一步步地跳转过来了,我会将内部的东西做一些优化,直接放到你那里,你执行这些指令即可

可是呢,为什么会出现链接错误❌

  • 因为在【预编译】的时候就要展开func.h这个头文件,但是在主调用接口中包含的头文件中只有函数的声明没有实现,此时只能在【链接】的时候展开了,但是在链接的时候因为只有声明所以只得到了函数名修饰后的地址。编译器便需要通过这个地址找到函数所在的位置,对于普通函数而言在这个时候就可以通过call找过去了,但是对于内联函数而言,却无法做到,因为它并没有【call】和【jmp】这些指令,因此就造成了链接错误的现象

那要如何去解决呢?

  • 若是这个函数要定义成内联函数的话,就不要将定义和声明分开了,在头文件中定义出来后就直接对其进行声明,便不会造成这样的问题了
// F.h
#include <iostream>
using namespace std;inline void f(int i)
{cout << i << endl;
}
//--------------------------
// main.cpp
#include "F.h"int main()
{f(10);return 0;
}

四、总结与提炼

好,最后来总结一下本文所学习的内容📖

  • 首先我们回顾来一下C语言中所学习的【宏】,经过了对宏的优缺点分析以及一些同学的错误案例对照,在面试的时候让你写一个宏,可不要写错了哦!
  • 接下去,我们就正式地开始介绍内联函数,对于内联函数来说,它不仅保留了宏的优点,没有函数调用建立栈帧的开销,而且还修复了宏的缺点,将其做成一个函数的形式,简洁直观,而且便于调试观察,提升程序运行的效率
  • 但是对于内联函数来说,也是存在要注意的地方,因为它也是会和宏一样在调用的地方展开,不过会进行一定程度的优化,可这种空间换时间的思想只适用于小型的函数,对于大型的函数不建议定义成【内联函数】,会造成程序的过多臃肿
  • 但是在看了内联函数的生成机制后,其实我们也不用担心在误用内联函数后使得程序变大,它会有一个自动判断的机制,若是你程序的行数过多的话,编译器就会忽略你的这请求,对于我们要将一个函数声明为内联函数其实是在向编译器发起一个申请,它可以选择接收也可以选择拒绝🙅‍

以上就是本文要介绍的所有内容,感谢您的阅读🌹

在这里插入图片描述

相关文章:

C++ | 对比inline内联函数和宏的不同点

文章目录一、前言二、宏的优缺点分析1、概念回顾2、宏的缺点3、宏的优点三、inline内联函数1、概念2、特性①&#xff1a;空间换时间&#x1f381;趣味杂谈&#xff1a;庞大的游戏更新包3、特性②&#xff1a;inline实现机制4、特性③&#xff1a;inline的声明与定义反汇编观察…...

面试官问 : ArrayList 不是线程安全的,为什么 ?(看完这篇,以后反问面试官)

前言 金三银四 &#xff1f; 也许&#xff0c;但是。 近日&#xff0c;又收到金三银四一线作战小队成员反馈的战况 &#xff1a; 我不管你从哪里看的面经&#xff0c;但是我不允许你看到我这篇文章之后&#xff0c;还不清楚这个面试问题。 本篇内容预告&#xff1a; Array…...

Linux串口应用编程

一、 串口API 在Linux系统中,操作设备的统一接口就是:open/ioctl/read/write。 对于UART,又在ioctl之上封装了很多函数,主要是用来设置行规程。 所以对于UART,编程的套路就是: open设置行规程,比如波特率、数据位、停止位、检验位、RAW模式、一有数据就返回read/write 怎么设置…...

java程序员学前端-HTML篇

HTML 与 CSS HTML 是什么&#xff1a;即 HyperText Markup language 超文本标记语言&#xff0c;咱们熟知的网页就是用它编写的&#xff0c;HTML 的作用是定义网页的内容和结构。 HyperText 是指用超链接的方式组织网页&#xff0c;把网页联系起来Markup 是指用 <标签>…...

【云原生|Docker】03-docker的基础操作

目录 前言 查询相关 容器相关 1. 容器启动 2. 容器关闭 3. 重启容器 4. 暂停容器 5. 删除容器 6. docker run参数汇总 镜像相关 1. 镜像推送至仓库 2. docker image load使用 3. docker image import使用 4. dokcer image参数汇总 前言 容器的命…...

vue2+高德地图web端开发使用

创建vue2项目我们创建一个vue2项目&#xff0c;创建vue2项目就不用再多说了吧&#xff0c;使用“vue create 项目名 ”创建即可注册高德地图高德地图官网地址&#xff1a;https://lbs.amap.com/如果是第一次使用&#xff0c;点击注册然后进入我们的控制台注册完之后进入控制台&…...

01背包问题c++

问题 问题介绍 有 N 种物品和一个容量是 V 的背包&#xff0c;每种物品都有无限件可用。 第 i 种物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第…...

ZYNQ硬件调试-------day2

ZYNQ硬件调试-------day2 1.ILA&#xff08;Integrated Logic Analyzer &#xff09; 监控逻辑内部信号和端口信号;可以理解为输出。可单独使用 2.VIO&#xff08;Virtual Input/Output &#xff09; 实时监控和驱动逻辑内部信号和端口信号&#xff0c;可以理解为触发输入。不可…...

JavaScript中Promise的简单使用及其原理

Promise是ES6最重要的特性之一&#xff0c;今天来系统且细致的研究一下Promise的用法以及原理。 按照我往常的理解&#xff0c;Promise是一个构造函数&#xff0c;有all、resolve、reject、then、catch等几个方法&#xff0c;一般情况下&#xff0c;在涉及到异步操作时才会用到…...

SpringBoot RabbitMQ 延时队列取消订单【SpringBoot系列14】

SpringCloud 大型系列课程正在制作中&#xff0c;欢迎大家关注与提意见。 程序员每天的CV 与 板砖&#xff0c;也要知其所以然&#xff0c;本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发 1 项目准备 SpringBoot 雪花算法生成商品订单…...

【论文阅读 WWW‘23】Zero-shot Clarifying Question Generation for Conversational Search

文章目录前言MotivationContributionsMethodFacet-constrained Question GenerationMultiform Question Prompting and RankingExperimentsDatasetResultAuto-metric evaluationHuman evaluationKnowledge前言 最近对一些之前的文章进行了重读&#xff0c;因此整理了之前的笔记…...

ouc 网络安全实验 格式化字符串漏洞

文章目录要求lab1lab2lab3lab4结语因为当时自己做实验的时候出现了很多疑问不会解决&#xff0c;在网上看到了一位大佬 王森ouc 的专栏文章解决了很多问题&#xff0c;也学到了很多知识和解决问题的方法&#xff0c;现在把我的实验解决方法也发上来&#xff0c;希望有不会的同…...

PMSM矢量控制笔记(1.1)——电机的机械结构与运行原理

前言&#xff1a;重新整理以前的知识和文章发现&#xff0c;仍然有许多地方没有学得明白&#xff0c;懵懵懂懂含含糊糊的地方多如牛毛&#xff0c;尤其是到了真正实际写东西或者做项目时&#xff0c;如果不是系统的学习了知识&#xff0c;很容易遇到问题就卡壳&#xff0c;也想…...

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题——中间人攻击渗透测试解析(详细)

B-4任务四:中间人攻击渗透测试 *任务说明:仅能获取Server4的IP地址 *任务说明:仅能获取Server11的IP地址 1.通过上题渗透后得到控制权限的服务器场景Server4进行查看本地的arp缓存表的操作,并将该操作所使用的命令作为Flag值提交; 2.通过上题渗透后得到控制权限的服务…...

MySQL必知必会 | 安全、维护、性能

全球化和本地化 关于MySQL处理不同字符集和语言 字符集和校对顺序 数据库被用来存储和检索数据&#xff0c;不同的语言和字符集需要以不同的方式存储和检索&#xff0c;因此&#xff0c;MySQL需要适应不同的字符集&#xff0c;适应不同的排序方式 一些术语&#xff1a; 字符…...

MaaS Model as a Service 模型即服务

大模型是人工智能的发展趋势和未来。大模型是“大算力强算法” 结合的产物。目前&#xff0c;大模型生态已初具规模。大模型能够实现 AI 从“手工作坊”到“工厂模式”的转变&#xff0c;大模型通常是在大规模无标注 数据上进行训练&#xff0c;学习出一种特征和规则&#xf…...

【编程基础】027.C语言中函数在解题中的应用(三)

文章目录C语言中函数的应用1、自定义函数实现二维数组的转置2、自定义函数之整数处理3、自定义函数之数字后移4、自定义函数之字符串拷贝C语言中函数的应用 1、自定义函数实现二维数组的转置 题目描述 写一个函数&#xff0c;使给定的一个二维数组&#xff08;&#xff13;&a…...

echart图表之highcharts

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、HighCharts是什么&#xff1f;二、使用步骤1.引入库2.前端代码3.展现结果4.后台自动截图总结前言 提示&#xff1a;这里可以添加本文要记录的大概内容&…...

关于.Net和Java的看法——我见过最牛的一个小实习生经历

1、背景 笔者&#xff08;小方同学在学习&#xff09;是一个专科院校的一名普通学生&#xff0c;目前就职于某三线城市的WEB方面.Net开发实习生&#xff0c;在找实习期间和就业期间的一些看法&#xff0c;发表此文&#xff0c;纯个人想法&#xff0c;欢迎讨论&#xff0c;指正…...

基于springboot+vue的“智慧食堂”程序设计实现【毕业论文,源码】

系统登录界面系统架构开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven浏览器&#xf…...

学计算机选择什么编程语言好一些?

工资水平的话&#xff0c;目前人工智能、大数据和云计算等领域的工资相对较高&#xff0c;但是要求也高&#xff0c;学历&#xff0c;学习能力什么的。然后是后端开发&#xff0c;Python、Java、C等编程语言的工资普遍较高。 不用开发语言的优势 ​Java&#xff1a;Java是一种…...

持续集成 在 Linux 上搭建 Jenkins,自动构建接口测试

本篇把从 0 开始搭建 Jenkins 的过程分享给大家&#xff0c;希望对小伙伴们有所帮助。 文章目录 在 Linux 上安装 Jenkins在 Linux 上安装 Git在 Linux 上安装 Python在 Linux 上安装 Allure配置 Jenkinsjenkins 赋能 - 使用邮箱发送测试报告jenkins 赋能 - 优化测试报告内容…...

MySQL学习笔记(总结)

1. 数据库服务器操作命令 启动数据库&#xff1a;net start mysql80 &#xff08;注释&#xff1a;windows命令&#xff09; 停止数据库&#xff1a;net stop mysql80 &#xff08;注释&#xff1a;windows命令&#xff09; 重启数据库&#xff1a;systemctl restart mysql;…...

Android开发 Layout布局 ScrollView

1.LinearLayout 属性 orientation&#xff1a;内部组件排列方式&#xff0c;可选vertical、horizontal&#xff0c;默认horizontal layout_weight: 与平级组件长宽比例&#xff0c;需要将layout_width、layout_height其中一个设置为0dp&#xff0c;表明长或宽与平级组件的长…...

手撕数据结构与算法——树(三指针描述一棵树)

&#x1f3c6;作者主页&#xff1a;king&南星 &#x1f384;专栏链接&#xff1a;数据结构 &#x1f3c5;文章目录&#x1f331;树一、&#x1f332;概念与定义二、&#x1f333;定义与预备三、&#x1f334;创建结点函数四、&#x1f340;查找五、&#x1f341;插入六、&a…...

字节跳动Java后端开发实习面经

最近在和同学一起找实习&#xff0c;投了b站、字节和miHoYo的后端开发。b站二月底就投了&#xff0c;但现在也还没回复&#xff1b;miHoYo也还没回复&#xff0c;估计是只面向24届了&#xff1b;感谢字节&#xff0c;给了我面试的机会。字节真的处理好快&#xff0c;不到一周官…...

STM32实战项目-触摸按键

前言&#xff1a; 通过触摸按键控制LED灯以及继电器&#xff0c;具体实现功能如下&#xff1a; 1、触摸按键1单击与长按&#xff0c;控制LED1&#xff1b; 2、触摸按键2单击与长按&#xff0c;控制LED2; 3、触摸按键3单击与长按&#xff0c;控制LED3; 4、触摸按键4单击与长…...

安全行业-术语(万字)

肉鸡 所谓“肉鸡”说一种很形象的比喻&#xff0c;比喻那些可以任意被我们控制的电脑&#xff0c;对方可以是Windows系统&#xff0c;也可以说UNIX/linux系统&#xff0c;可以说普通的个人电脑&#xff0c;也可以是大型的服务器&#xff0c;我们可以像操作自己的电脑那样来操控…...

P1113 杂务(拓扑排序 or 记忆回溯)

题目描述 John的农场在给奶牛挤奶前有很多杂务要完成&#xff0c;每一项杂务都需要一定的时间来完成它。比如&#xff1a;他们要将奶牛集合起来&#xff0c;将他们赶进牛棚&#xff0c;为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的&#xff0c;因为这样才有更…...

Web3中文|政策影响下的新加坡Web3步伐喜忧参半

如果说“亚洲四小龙”是新加坡曾经的荣耀&#xff0c;那么当时代进入21世纪的第二个十年&#xff0c;用新加坡经济协会&#xff08;SEE&#xff09;副主席、新加坡新跃社科大学教授李国权的话来说&#xff0c;新加坡现在的“荣耀”是全球金融的主要“节点”或区块链行业发展的关…...

如何欣赏网站/搜索到的相关信息

这篇文章为大家分享了最准确的php截取字符串长度函数&#xff0c;最精确的截取长度&#xff0c;大家可以在此基础上进行改进&#xff0c;感兴趣的小伙伴们可以参考一下说是最精确截取长度&#xff0c;其实我也不敢确定是否是最精确的&#xff0c;具体有多精确看下面的效果就知道…...

国内it外包龙头企业/衡阳seo优化首选

2019独角兽企业重金招聘Python工程师标准>>> Sublime Text http://www.sublimetext.com 官网 http://www.sublimetext.com/2 官网 http://www.sublimetext.com/3 官网 1、插件安装 直接安装下载插件&#xff0c;解压至Packages文件夹中。在这里可以打开Packages文件…...

lnmp怎么做网站/淄博seo培训

文章目录MySQL 数据类型介绍数值类型日期/时间类型字符串类型int(4)、int(8)、int(11) 分别占用几个字节 &#xff1f;MySQL 中的整数型数据类型&#xff1a;不同整数类型的取值范围&#xff1a;回归正题&#xff0c;int(4)、int(8)、int(11) 究竟占用几个字节呢 &#xff1f;再…...

手机模板网站/网站推广如何做

计算机软件著作权登记分类号如何选择&#xff1f; 回答&#xff1a;在向中国版权保护中心&#xff08;http://www.ccopyright.com.cn/ &#xff09;申请计算机软件著作权的时候&#xff0c;需要填写一表单【分类号】&#xff0c;这个分类号&#xff0c;很多人不知道如何选择。…...

网站宣传的方式/阿里云搜索引擎入口

gMLP & aMLP&#xff1a;带门控的MLP 摘要 Transformers已经成为深度学习中最重要的架构创新之一&#xff0c;并且在过去几年里实现了许多突破。在这里&#xff0c;我们提出了一个简单的、注意力无关的网络架构&#xff0c;即gMLP&#xff0c;该架构仅仅基于带有门控的MLP…...

海东网站建设公司/怎样联系百度客服

作为一个开发人员&#xff0c;在看别人项目或者看第三方库的源代码时&#xff0c;可能经常会看到譬如a>>4&0x0f这样的写法&#xff0c;对于一些初入行的童鞋来说可能就不是太明白这是什么意思。下面我们就来讲解这几个运算符的实际用途。 一、运算符的含义 运算符含…...