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

C语言详解(预编译)

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
💥💥个人主页:奋斗的小羊
💥💥所属专栏:C语言

🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。


目录

  • 前言
    • 1、预定义符号
    • 2、#define定义常量和标识符
    • 3、#define定义宏
    • 4、带有副作用的宏参数
    • 5、宏替换的规则
    • 6、宏和函数的对比
    • 7、# 和
      • 7.1 #运算符
      • 7.2 ##运算符
    • 8、命名的约定
    • 9、#undef
    • 10、命令行定义
    • 11、条件编译
    • 12、头文件的包含
      • 12.1 头文件被包含的方式
        • 12.1.1 本地文件包含
        • 12.1.2 库文件包含
      • 12.2 嵌套文件的包含
  • 总结

前言

本篇文章将详细介绍编译过程中预编译的具体细节
在C语言的学习中部分人可能会忽视这一部分的学习,因为像VS这样相对强大的集成开发环境,我们在写好代码后只需要开始执行即可,所以部分人认为这一部分不值得我们花费时间去学习
其实不然,学习C语言预编译过程可以帮助我们更深入地了解C语言的编译过程和语法特性,提高代码编写的效率和质量,以及拓展编程技能


1、预定义符号

C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预编译阶段处理的

  • __FILE__:正在编译的源文件的文件名
  • __LINE__:文件当前的行号
  • __DATE__:文件被编译的日期
  • __TIME__:文件被编译的时间
  • __STDC__:如果编译器遵循 ANSI C,其值为1,否则未定义

例如:

在这里插入图片描述


2、#define定义常量和标识符

#define定义的常量和标识符在预编译阶段完成替换

基本语法:

#define name stuff

特别的,为了区分普通常量这个name我们一般用大写形式
比如:

#define MAX 10000
#define REG register

#define后面的代码理论上讲只能写一行,但是如果后面的代码过长,我们可以使用'\'来实现换行,相当于转义转义字符'\'转义了转义字符'\n'

#define DEBUG_PRINT printf("file:%s\tline:%d\t\date:%s\ttime:%s\n,\__FILE__,__LINE__,\__DATE__,__TIME__)

值得注意的是,行末最好不要加;,在某些场景下是没什么问题,但是在大多数情况下是有语法错误的,所以我们要养成良好的编程习惯,行末不加;


3、#define定义宏

#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)
基本语法:

#define name(parament_list) stuff

其中parament-list(参数列表)是一个由逗号隔开的符号表,它们可能出现在stuff

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

举例:输入一个数,输出它的平方数

#include <stdio.h>
#define SQUARE(x) x*xint main()
{int n = 0;scanf("%d", &n);int ret = SQUARE(n);printf("%d\n", ret);return 0;
}

在这里插入图片描述

上面的代码看似没有什么问题,但当我们想计算n+1的平方数时,就会出现问题:

#include <stdio.h>
#define SQUARE(x) x*xint main()
{int n = 0;scanf("%d", &n);int ret = SQUARE(n + 1);printf("%d\n", ret);return 0;
}

在这里插入图片描述

这是为什么呢?

原因就是带参数的宏在替换的时候括号内的表达式是不做任何计算的

也就是说,上面替换后的形式是:5 + 1 * 5 + 1,为了解决这个问题,我们可以在定义宏的时候给x加上括号:

#define SQUARE(x) (x)*(x)

这样替换后的结果就变成了:(5 + 1)*(5 + 1),但是这样给单独的参数加括号的形式在某些场景下还是存在问题,比如:

#include <stdio.h>
#define SQUARE(x) (x)+(x)int main()
{int n = 0;scanf("%d", &n);int ret = 5 * SQUARE(n + 1);printf("%d\n", ret);return 0;
}

在这里插入图片描述

那为了解决这个问题,我们可以(x)+(x)整体加上括号:((x) + (x))

#include <stdio.h>
#define SQUARE(x) ((x)+(x))int main()
{int n = 0;scanf("%d", &n);int ret = 5 * SQUARE(n + 1);printf("%d\n", ret);return 0;
}

在这里插入图片描述

所以,在写宏的时候一定不要吝啬括号


4、带有副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果,副作用就是表达式求值的时候出现的永久性效果
例如:

  • x + 1; //不带副作用
  • x++; //带有副作用

上面两个表达式的值是相同的,但是第一个表达式x的本身没有发生改变,而第二个表达式x本身发现了改变,这就是副作用

例如:使用宏实现求两个数的较大值

#include <stdio.h>
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{int a = 10;int b = 20;int ret = MAX(a, b);printf("%d\n", ret);return 0;
}

在这里插入图片描述

上面代码中宏参数在宏定义中出现了两次,我们使用MAX(a, b);时没什么问题,但当我们使用MAX(a++, b++);时问题就会出现:

#include <stdio.h>
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{int a = 10;int b = 20;int ret = MAX(a++, b++);printf("%d\n", ret);printf("a = %d, b = %d\n", a, b);return 0;
}

在这里插入图片描述

可以发现a和b的值会发生改变,就是表达式求值的时候出现了永久性效果。

与函数对比:

#include <stdio.h>int MAX(int x, int y)
{printf("a = %d, b = %d\n", x, y);return (x > y ? x : y);
}int main()
{int a = 10;int b = 20;int ret = MAX(a++, b++);printf("%d\n", ret);return 0;
}

请添加图片描述

从上面的代码中可以看出来,带参数的宏替换和函数传参是非常相似的,但是它们的传参是有本质区别的。
带参数的宏替换是直接将参数做整体替换,替换过后的表达式是:((a++)>(b++)?(a++):(b++));而函数参过后的表达式是:(a > b ? a : b)


5、宏替换的规则

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

  • 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号,如果有,它们首先被替换
  • 替换文本随后被插入到程序中原来文本的位置,对于宏,参数名被他们的值所替换
  • 最后,再次对结果文件进行扫描,看看是否包含任何由#define定义的符号,如果有,重复上述步骤

例如:

#include <stdio.h>
#define M 10
#define N M + 2
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{int ret = MAX(M, N);return 0;
}

MAX(M, N)首先被替换成:((10)>(M + 2)?(10):(M + 2))
然后((10)>(M + 2)?(10):(M + 2))再被替换成:((10)>(10 + 2)?(10):(10 + 2))

注意:

  • 宏参数和#define定义中可以出现其他#define定义的符号,但宏不能实现递归

比如:#define N M + 2这个是可以的,但#define N N + 2是不行的。

  • 当预处理器搜索#define定义的符号时,字符串常量的内容并不被搜索

比如:

#include <stdio.h>
#define M 10
#define N M + 2
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{printf("MAX(M, N)");return 0;
}

请添加图片描述

可以看到宏MAX(M, N)并没有展开。


6、宏和函数的对比

宏通常被应用于执行简单的运算。

比如在两个数中找较大数,用宏实现更有优势:

#define MAX(x, y) ((x)>(y)?(x):(y))

那为什么不用函数呢?原因有二:

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作需要的时间更多,函数调用还需要一些入栈出栈的过程,所以宏比函数在程序的规模和速度方面更胜一筹
  2. 更为重要的是函数的参数必须声明为特定的类型,所以函数只能在类型合适的表达式上使用。但宏可以使用于整型、长整型、浮点型等可以用于>来比较的类型,宏参数是无关类型的

但是和函数相比宏还是有劣势的:

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中,除非宏比较短,否则可能大幅度增加程序的长度
  2. 宏是不能调试的
  3. 宏由于无关类型,也就不够严禁,所以宏定义是不够安全的
  4. 宏可能会带来运算符优先级的问题,导致程序容易出错

宏有时候能做到函数做不到的事,比如:宏的参数可以出现类型,但是函数不行

#include <stdio.h>
#define MALLOC(n, type) (type*)malloc(n * sizeof(type))int main()
{//int* p = (int*)malloc(10 * sizeof(int));int* p = MALLOC(10, int);//int *p = (int*)malloc(10 * sizeof(int));return 0;
}

宏和函数的对比:

属性#define定义宏函数
代码长度每次使用时,宏代码都会被插入到程序中,除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方,每次使用这个函数时,都调用那个地方的用一份代码
执行速度更快存在函数的调用和返回的额外开销,所以相对慢一些
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的结果,所以建议宏在书写的时候多写括号函数参数只在函数调用的时候求值一次,它的结果值传递给函数,表达式的求值结果更容易预测
带有副作用的参数参数可能被替换到宏体中的多个位置,如果宏的参数被多次计算,带有副作用的参数求值可能会产生不可预测的结果函数参数只在传参的时候求值一次,结果更容易控制
参数类型宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用任何参数类型函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的
调试宏是不方便调试的函数是可以逐语句调试的
递归宏是不能递归的函数是可以递归的

7、# 和

7.1 #运算符

#运算符将宏的一个参数转换为字符串字面量,它仅允许出现在带参数的宏的替换列表中
#运算符所执行的操作可以理解为“字符串化
比如:当我们有一个变量int a = 10;的时候,我们想打印出:the value of a is 10.
下面是常规写法:

#include <stdio.h>int main()
{int a = 10;printf("the value of a is %d\n", a);return 0;
}

如果我们想把打印的这条代码通过宏替换来实现,该怎么做呢?

#include <stdio.h>
#define PRINT(format, n) printf("the value of n is "format"\n", n)int main()
{int a = 10;PRINT("%d", a);//printf("the value of n is ""%d""\n", a);return 0;
}

如果写成上面这种代码很明显并没有解决问题,因为如果我们将n写成%d时并不能打印出a,而只能打印出a的值,那为了能打印出a本身的字面量,我们就可以使用#操作符
如下:

#include <stdio.h>
#define PRINT(format, n) printf("the value of "#n" is "format"\n", n)int main()
{int a = 10;PRINT("%d", a);//printf("the value of "a" is ""%d""\n", a);double b = 3.14;PRINT("%lf", b);//printf("the value of "b" is ""%lf""\n", b);return 0;
}

请添加图片描述

所以我们说:#运算符所执行的操作可以理解为“字符串化”,上面的代码中是将a和b字符串化了。

当n = a的时候,#n 就相当于“a”


7.2 ##运算符

##可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。##被称为记号粘合
这样的连接必须产生一个合法的标识符,否则其结果就是未定义的。

比如现在有这么一个问题:当我们写一个函数来求两个数的较大值的时候,不同的类型我们就需要写不同的函数,这样写太繁琐了,我们可以使用宏来简化这件事:

#include <stdio.h>
#define GENERIC(type) \
type type##_max(type x, type y)\
{\return ((x) > (y) ? (x) : (y));\
}GENERIC(int)
//int int_max(int x, int y)
//{
//	return ((x) > (y) ? (x) : (y));
//}GENERIC(double)
//double double_max(double x, double y)
//{
//	return ((x) > (y) ? (x) : (y));
//}int main()
{printf("%d\n", int_max(10, 20));printf("%lf\n", double_max(3.14, 6.28));return 0;
}

请添加图片描述

上面的代码中我们利用宏替换来实现创建不同类型的函数,type##_max中的##操作符将type_max连接成了一个新的标识符


8、命名的约定

一般来讲函数和宏的使用语法很相似,所以语言本身没法帮我们区分二者,那我们平时的习惯是:

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

9、#undef

#undef这条指令用于移除一个宏定义

#include <stdio.h>
#define M 10int main()
{printf("%d\n", M);
#undef Mprintf("%d\n", M);return 0;
}

请添加图片描述

如果现存的一个宏名需要被重新定义,那么它的旧名字首先需要被移除


10、命令行定义

许多C编译器提供了一种能力,允许在命令行中定义符号,用于启动编译过程。
例如:当我们根据同一个源文件想要编译出一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个一定长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大些,我们需要一个较大的数组)

编译指令:

//linux  环境演示
gcc -D ARRAY_SIZE=10 programe.c

11、条件编译

满足条件,就参与编译;不满足条件,就不参与编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的,因为我们有条件编译指令:

1.
#if   常量表达式   //常量表达式由预处理器求值
//...
#endif如:
#define _DEBUG_ 1
int main()
{
#if _DEBUG_printf("a");
#endifreturn 0;
}
2.多个分支的条件编译
#if   常量表达式
//...
#elif   常量表达式
//...
#else
//...
#endif如:
#define M 1
int main()
{
#if M == 1printf("a");
#elif M == 2printf("b"):
#elseprintf("C");
#endifreturn 0;
}
3.判断是否被定义
//如果定义了
#if defined(symbol)
#ifdef symbol如:
#define M 2
int main()
{
#ifdef Mprintf("a");
#endifreturn 0;
}//如果没定义
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#ifdef OS_UNIX#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2():#endif
#endif

条件编译通常用于跨平台性代码的编译


12、头文件的包含

12.1 头文件被包含的方式

12.1.1 本地文件包含

一般指自己创建的头文件

#include "filename.h"

查找策略:
先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件,如果找不到就提示编译错误。


12.1.2 库文件包含

一般指标准库中头文件的包含

#include <filename.h>

查找策略:
直接去标准路径下去查找,如果找不到就提示编译错误。
那这样是不是就说明,对库文件也可以使用" "的形式包含呢?
答案是可以的。但是这样查找的效率比较低,也不容易区分是库文件还是本地文件


12.2 嵌套文件的包含

我们已经知道,#include指令可以使另外一个文件被编译,就像它实际出现于#include指令的地方一样。
这种替换的方式很简单:预编译器先删除这条指令,并用包含文件的内容替换
一个头文件被包含几次,就会被实际编译几次,如果重复包含,对编译的压力就比较大

#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"int main()
{return 0;
}

如果像上面这样写,test.h文件的内容就会被拷贝5份
如果test.h文件比较大,这样预处理后代码量会剧增,如果工程比较大,有公共使用的文件,被大家都能用,又不做任何的处理,那么后果会不堪设想。
为了解决头文件被重复引入的问题,就要用到条件编译
我们在每个头文件的开头这样写:

#ifndef __FILENAME_H__
#define __FILENAME_H__//...#endif

或者

#pragma once

就可以避免头文件的重复引入。


总结

  • 增强对C语言编译过程的整体理解:预编译是C语言编译过程的第一阶段,在预编译阶段可以对源代码进行预处理,如宏定义、头文件包含等。通过学习预编译过程,可以更全面地理解C语言代码的编译过程。
  • 优化代码结构:预编译指令能够简化代码结构、提高代码的重用性和可维护性。学习预编译过程可以帮助程序员更好地利用预编译指令优化代码结构,提高代码的质量。
  • 理解条件编译和跨平台编译:条件编译是预编译指令中的重要功能,可以根据不同条件编译不同的代码。通过学习预编译过程,可以了解如何使用条件编译来实现跨平台编译,提高代码的可移植性。

相关文章:

C语言详解(预编译)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…...

解决el-table表格拖拽后,只改变了数据,表头没变的问题

先看看是不是你想要解决的问题 拖拽后表头不变的bug修复 这个问题一般是使用v-for对column的数据进行循环的时候&#xff0c;key值绑定的是个index导致的&#xff0c;请看我上篇文章&#xff1a;eleplus对el-table表格进行拖拽(使用sortablejs进行列拖拽和行拖拽)&#xff1a;-…...

简单塔防小游戏

学习目标&#xff1a;熟悉塔防游戏核心战斗 游戏画面 项目结构目录 核心代码&#xff1a; if ( Input.GetMouseButtonDown(0)){if (EventSystem.current.IsPointerOverGameObject()false){//开发炮台的建造Ray ray Camera.main.ScreenPointToRay(Input.mousePosition);Rayca…...

高考之后第一张大流量卡应该怎么选?

高考之后第一张大流量卡应该怎么选&#xff1f; 高考结束后&#xff0c;选择一张合适的大流量卡对于准大学生来说非常重要&#xff0c;因为假期期间流量的使用可能会暴增。需要综合考虑多个因素&#xff0c;以确保选到最适合自己需求、性价比较高且稳定的套餐。以下是一些建议…...

如何从微软官方下载Edge浏览器的完整离线安装包

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 正文内容 📒🚀 官方直链下载🚬 手动选择下载🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 在网上搜索Microsoft Edge浏览器的离线安装包时,很多用户都会发现大部分都是在线安装包,无法满足他们在无网络环境下进…...

git 常用的命令

git 常用的命令 一、基础命令1.1 初始化1.2 添加文件1.3 查看缓存区中的文件1.4 查看上次提交到缓存区中的文件1.5 文件从缓存区取出1.6 提交文件1.6 查看提交中包含的文件1.7 查看commit记录 二、回退命令2.1 git reset2.2 将文件从暂存区取出2.3 将文件从仓库取出2.3.1 保留工…...

【StableDiffusion】Embedding 底层原理,Prompt Embedding,嵌入向量

Embedding 是什么&#xff1f; Embedding 是将自然语言词汇&#xff0c;映射为 固定长度 的词向量 的技术 说到这里&#xff0c;需要介绍一下 One-Hot 编码 是什么。 One-Hot 编码 使用了众多 5000 长度的1维矩阵&#xff0c;每个矩阵代表一个词语。 这有坏处&#xff0c…...

计算机网络(2) 网络层:IP服务模型

一.Internet Protocol在TCP/IP四层模型中的作用 第三层网络层负责数据包从哪里来到哪里去的问题。传输层的数据段提交给网络层后&#xff0c;网络层负责添加IP段&#xff0c;包含数据包源地址与目的地址。将添加IP段的数据包交由数据链路层添加链路头形成最终在各节点传输中所需…...

新人学习笔记之(初识C语言)

一、C语言的简介 1.C语言&#xff1a;1978年1月1日美国贝尔实验室推出的一门非常哇塞计算机语言 2.计算机语言&#xff1a;人与计算机之间进行信息交流沟通的一种特殊语言 二、C语言能做什么 1.操作系统 2.驱动开发 3.引擎开发 4.游戏开发 5.嵌入式开发 三、学习C语言的好处 …...

Unity EasyRoads3D插件使用

一、插件介绍 描述 Unity 中的道路基础设施和参数化建模 在 Unity 中使用内置的可自定义动态交叉预制件和基于您自己导入的模型的自定义交叉预制件&#xff0c;直接创建独特的道路网络。 添加额外辅助对象&#xff0c;让你的场景栩栩如生&#xff1a;桥梁、安全护栏、栅栏、墙壁…...

Redis 地理散列GeoHash

用数据库来算附近的人 地图元素的位置数据使用二维的经纬度表示&#xff0c;经度范围&#xff08;-180&#xff0c;180]&#xff0c;纬度范围 &#xff08;-90&#xff0c;90],纬度正负以赤道为界&#xff0c;北正南负&#xff0c;经度正负已本初子午线&#xff08;英国格林尼…...

vim 显示行号

在 Vim 中&#xff0c;你可以通过几种不同的方式来显示行号。以下是两种常用的方法&#xff1a; 临时显示行号&#xff1a; 当你打开 Vim 并想要临时查看文件的行号时&#xff0c;你可以使用 :set number 命令。这个命令会在当前 Vim 会话中显示行号。如果你想要关闭行号显示&a…...

C++:调整数组顺序使奇数位于偶数前面【面试】

在C&#xff0c;如果要调整数组顺序使所有奇数位于偶数前面&#xff0c;这里提供一种简单且常用的方法&#xff1a;双指针技术。这种方法不需要额外的空间&#xff0c;并且时间复杂度为O(n)。 以下是使用双指针技术实现的示例代码&#xff1a; #include <iostream> #in…...

WPF/C#:程序关闭的三种模式

ShutdownMode枚举类型介绍 ShutdownMode是一个枚举类型&#xff0c;它定义了WPF应用程序的关闭方式。这个枚举类型有三个成员&#xff1a; OnLastWindowClose&#xff1a;当最后一个窗口关闭或者调用System.Windows.Application.Shutdown方法时&#xff0c;应用程序会关闭。O…...

登录/注册- 滑动拼图验证码(IOS/Swift)

本章介绍如何使用ios开发出滑动拼图验证码&#xff0c;分别OC代码和swift代码调用 1.导入项目model文件OC代码&#xff08;下载完整Demo&#xff09; 2.放入你需要显示的图片 一&#xff1a;OC调用 #import "ViewController.h" #import "CodeView.h"…...

MyBatis进行模糊查询时SQL语句拼接引起的异常问题

项目场景&#xff1a; CRM项目&#xff0c;本文遇到的问题是在实现根据页面表单中输入条件&#xff0c;在数据库中分页模糊查询数据&#xff0c;并在页面分页显示的功能时&#xff0c;出现的“诡异”bug。 开发环境如下&#xff1a; 操作系统&#xff1a;Windows11 Java&#…...

网站调用Edge浏览器API:https://api-edge.cognitive.microsofttranslator.com/translate

Edge浏览器有自带的翻译功能&#xff0c;在运行pc项目可能会遇到疯狂调用Edge的API https://api-edge.cognitive.microsofttranslator.com/translate 这个URL&#xff08;https://api-edge.cognitive.microsofttranslator.com/translate&#xff09;指向的是微软服务中的API接…...

css实现优惠券样式

实现优惠券效果&#xff1a; 实现思路&#xff1a; 需要三个盒子元素&#xff0c;使用 css 剪裁&#xff0c;利用 ellipse 属性&#xff0c;将两个盒子分别裁剪成两个半圆&#xff0c;位置固定在另一个盒子元素左右两边适当位置上。为另一个盒子设置想要的样式&#xff0c;圆角…...

函数递归(C语言)(详细过程!)

函数递归 一. 递归是什么1.1 递归的思想1.2 递归的限制条件 二. 递归举例2.1 求n的阶乘2.2 按顺序打印一个整数的每一位 三. 递归与迭代3.1 求第n个斐波那契数 一. 递归是什么 递归是学习C语言很重要的一个知识&#xff0c;递归就是函数自己调用自己&#xff0c;是一种解决问题…...

uniapp 接口请求封装

根目录下创建 config目录 api.js request.js // request.js // 封装一个通用的网络请求函数 适当调整 function httpRequest(options) {const userToken uni.getStorageSync(access_token).token;return new Promise((resolve, reject) > {uni.request({url: ${options.ur…...

C++中的观察者模式

目录 观察者模式&#xff08;Observer Pattern&#xff09; 实际应用 股票价格监控系统 发布-订阅系统 总结 观察者模式&#xff08;Observer Pattern&#xff09; 观察者模式是一种行为型设计模式&#xff0c;它定义了对象间的一对多依赖关系。当一个对象的状态发生改变…...

conda虚拟环境,安装pytorch cuda cudnn版本一致,最简单方式

1、pytorch版本安装&#xff08;卸载也会有问题&#xff09; &#xff08;1&#xff09;版本如何选择参考和卸载 https://zhuanlan.zhihu.com/p/401931724 &#xff08;2&#xff09;对应版本如何安装命令 https://pytorch.org/get-started/previous-versions/ 最简答安装参考…...

第 5 章:面向生产的 Spring Boot

在 4.1.2 节中&#xff0c;我们介绍了 Spring Boot 的四大核心组成部分&#xff0c;第 4 章主要介绍了其中的起步依赖与自动配置&#xff0c;本章将重点介绍 Spring Boot Actuator&#xff0c;包括如何通过 Actuator 提供的各种端点&#xff08;endpoint&#xff09;了解系统的…...

在 Windows 操作系统中,可以通过命令行工具来杀死进程

1. 使用 taskkill 命令 taskkill 命令是一个用于终止进程的命令行工具&#xff0c;可以通过进程名称或进程 ID (PID) 来杀死进程。 按进程名称杀死进程 taskkill /IM processname.exe /Fprocessname.exe 是进程的名称。/F 参数表示强制终止进程。 例如&#xff0c;终止名为…...

uni-app文件下载 h5 xls 乱码 锟斤拷 Blob pdf打不开

原先下载方式&#xff0c;PC管理端和浏览器打开文件能下载&#xff0c;xls没出现乱码&#xff0c;pdf能正常显示,H5下载xls乱码锟斤拷&#xff0c;PDF显示空白内容 怀疑是前端问题&#xff0c;也尝试过修改后端代码 后端设置编码格式 response.setCharacterEncoding(characte…...

Vue25-内置指令02:v-text指令

一、v-html对比v-text v-html支持结构的解析&#xff0c;v-text不支持结构的解析。 二、v-html的安全性问题 2-1、cookie的原理&#xff08;node.js&#xff09; 7天免登录&#xff0c;cookie实现。 cookie的本质就是类似于json的字符串&#xff0c;格式是&#xff1a;key-va…...

stable diffusion中的negative prompt是如何工作的

https://stable-diffusion-art.com/how-negative-prompt-work/https://stable-diffusion-art.com/how-negative-prompt-work/https://zhuanlan.zhihu.com/p/644879268...

STM32项目分享:智能小区充电桩系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…...

PDU模块中浪涌保护模块与空开模块的应用

由于PDU具体应用的特殊性&#xff0c;其在规划设计时具有应用场景的针对性&#xff0c;同时PDU的高度定制化的特点&#xff0c;是其他电气联接与保护产品所不具备的。 PDU基础的输出输入功能外&#xff0c;其电路的控制与电压保护器同时也极为重要。空气开关和浪涌保护器相关功…...

19、Go Gin框架集成Swagger

介绍&#xff1a; Swagger 支持在 Gin 路由中使用一系列注释来描述 API 的各个方面。以下是一些常用的 Swagger 注释属性&#xff0c;这些属性可以在 Gin 路由的注释中使用&#xff1a; Summary: 路由的简短摘要。Description: 路由的详细描述。Tags: 用于对路由进行分类的标…...

中国建设银行个人登录/无锡网络优化推广公司

Spring Boot总体来说&#xff0c;搭建还是比较容易的&#xff0c;特别是Spring Cloud全家桶&#xff0c;简称亲民微服务。但在发展趋势中&#xff0c;容器化技术已经成熟&#xff0c;面对巨耗内存的Spring Boot&#xff0c;小公司表示用不起。如今&#xff0c;很多刚诞生的JAVA…...

申请网站官网/如何网上销售自己的产品

来源&#xff1a;人民网准确监测方舱医院大量感染患者的生命状况&#xff0c;精确“诊断”大桥工程结构是否存在安全隐患&#xff0c;随时随地获取独居老人在家的健康体征……上海交通大学彭志科教授团队研发的基于微波感知的微动监测与环境智能前瞻技术&#xff0c;像一种神奇…...

东莞网站制作功能/郑州网站排名优化公司

python继承用法程序举例...

营销培训体系/海外网站seo优化

2019独角兽企业重金招聘Python工程师标准>>> 1、tomcat 启动报 processEngine NullPointerException&#xff0c; Service 层用到的activiti 的几个工具类都包无法注入的问题&#xff0c;Error creating bean with name processEngine 解决&#xff1a; 中午的时候将…...

商城网站开发/推广平台怎么做

Prometheus(也叫普罗米修斯)官网&#xff1a;https://prometheus.io/docs/introduction/overview/Grafana官网&#xff1a;https://grafana.com/enterprise特征普罗米修斯的主要特点是&#xff1a;具有由度量名称和键/值对标识的时间序列数据的多维数据模型一个灵活的查询语言 …...

湖南做网站 e磐石网络/常州seo外包

文章目录安装前准备安装 Oracle_Client安装PLSQL配置 Oracle客户端远程链接服务端安装前准备 Windows服务器 - 1Oracle_11g 数据库Windows服务器 - 2PLSQL、oracle_ClientWindows服务器防火墙关闭状态 安装 Oracle_Client Oracle_Client 下载地址&#xff0c;请点击此处 下载…...