C语言--预处理详解
预处理详解
1. 预定义符号
C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。
__FILE__
//进行编译的源文件__LINE__
//文件当前的行号__DATE__
//文件被编译的日期__TIME__
//文件被编译的时间__STDC__
//如果编译器遵循ANSI C,其值为1,否则未定义
举个例子:
printf("file:%s line:%d\n", __FILE__, __LINE__);
2. #define定义常量
基本语法:
#define name stuff
举个例子:
#define MAX 1000
#define reg register //为 register这个关键字,创建一个简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //在写case语句的时候自动把 break写上。// 如果定义的 stuff过⻓,可以分成⼏⾏写,除了最后⼀⾏外,每⾏的后⾯都加⼀个反斜杠(续⾏符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ , \__DATE__,__TIME__ )
思考:在define
定义标识符的时候,要不要在最后加上 ;
?
比如:
#define MAX 1000;
#define MAX 1000
建议不要加上 ;
,这样容易导致问题。
比如下面的场景:
if(condition)max = MAX;
elsemax = 0;
如果是加了分号的情况,等替换后,if
和else
之间就是2条语句,而没有大括号的时候,if
后边只能有一条语句。这时会出现语法错误。
3. #define定义宏
#define
机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
下方是宏的声明方式:
#define name( parament-list ) stuff
其中的 parament-list
是⼀个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的 ⼀部分。
举例:实现一个宏,求平方
#define SQUARE( x ) x * x
这个宏接收⼀个参数x
.如果在上述声明之后,你把 SQUARE( 5 )
; 置于程序中,预处理器就会⽤ 下⾯这个表达式替换上⾯的表达式: 5 * 5
警告:
这个宏存在⼀个问题:
观察下⾯的代码段:
int a = 5;
printf("%d\n" ,SQUARE( a + 1) );
乍⼀看,你可能觉得这段代码将打印36,事实上它将打印11,为什么呢?
替换⽂本时,参数x被替换成a+1,所以这条语句实际上变成了:
printf ("%d\n",a + 1 * a + 1 );
这样就⽐较清晰了,由替换产⽣的表达式并没有按照预想的次序进⾏求值。
在宏定义上加上两个括号,这个问题便轻松的解决了:
#define SQUARE(x) (x) * (x)
这样预处理之后就产⽣了预期的效果:
printf ("%d\n",(a + 1) * (a + 1) );
这⾥还有⼀个宏定义:
#define DOUBLE(x) (x) + (x)
定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5;
printf("%d\n" ,10 * DOUBLE(a));
这将打印什么值呢?看上去,好像打印100,但事实上打印的是55.
我们发现替换之后:
printf ("%d\n",10 * (5) + (5));
乘法运算先于宏定义的加法,所以出现了 55 . 这个问题,的解决办法是在宏定义表达式两边加上⼀对括号就可以了。
#define DOUBLE( x) ( ( x ) + ( x ) )
提⽰:
所以⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的 操作符或邻近操作符之间不可预料的相互作⽤。
4. 带有副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。
例如:
int a = 10;
int b = a + 1;//b = 11 a = 10
int b = ++a; //b = 11 a = 11
上述表达式中对于b来说都是11,但是对于a来说第一个表达式没有改变a的值但是第二个表达式改变了a的值。
x+1;//不带副作⽤(不对x原本的值进行改变)
x++;//带有副作⽤(会对x中原本的值改变掉)
MAX宏可以证明具有副作⽤的参数所引起的问题。
\#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);//输出的结果是什么?
这⾥我们得知道预处理器处理之后的结果是什么:
z = ( (x++) > (y++) ? (x++) : (y++));5 > 8 ? 6 : 9
从左向右依次运算,所以输出的结果是:x=6 y=10 z=9
总结:
- 在程序中使用宏定义,主要要明白宏的作用是替换,在预处理阶段会把程序中的宏名都换成宏体,所以如果发生这种使用两次相同的变量,并且两次变量的值还发生了改变,就会导致结果出错。
- 但是如果以函数的方式编写上述代码则不会出现这种问题,因为函数的传参是一次性的,后续如果改变这个变量的值也仅仅会在下一次重新进入这个函数时才会将改变的变量值传给函数。
5. 宏替换的规则
在程序中扩展#define
定义符号和宏时,需要涉及几个步骤:
-
在调用宏时,首先对参数进行检查,看看是否包含任何由
#define
定义的符号。如果是,它们首先被替换。**eg:**示例代码第8行
int m = MAX(M, 15);
,在进行宏替换的时候,会先检测参数中有没有宏名,所以在此行代码中先将M替换。 -
替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
**eg:**示例代码第8行
int m = MAX(M, 15);
,在经过规则一之后明白了需要先替换参数M,为100。 -
最后,再次对结果文件进行扫描,看看它是否包含任何由
#define
定义的符号。如果是,就重复上述处理过程。**eg:**示例代码第8行
int m = MAX(M, 15);
,在替换掉参数中的宏定义之后,也检测完确保参数中没有宏名之后,最后替换MAX。
注意:
-
宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
**eg:**示例代码第2行
#define N M+1
,可以对已经进行宏定义的M继续作为N的宏定义条件。 -
当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
**eg:**示例代码第9行
printf("MAX(M. 15)");
,最后打印在屏幕上的就是MAX(M. 15),并不是将里面的宏进行替换。
示例代码:
#define M 100
#define N M+1#define MAX(x, y) ((x)>(y)?(x):(y))int maim()
{int m = MAX(M, 15);printf("MAX(M, 15)");return 0;
}
6. 宏函数的对比
宏通常被应用于执行简单的运算。
例如在两个数中找出较大的一个时,写成下面的宏,更有优势一些。
#define MAX(a, b) ((a) > (b) ? (a) : (b))
那为什么不⽤函数来完成这个任务?
原因有⼆:
-
⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐函数在程序的规模和速度⽅⾯更胜⼀筹。
-
更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之 这个宏怎可以适⽤于整形、⻓整型、浮点型等可以⽤于
>
来⽐较的类型。宏的参数是类型⽆关的。
和函数相⽐宏的劣势:
-
每次使⽤宏的时候,⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短,否则可能⼤幅度增加程序 的⻓度。
-
宏是没法调试的。
-
宏由于类型⽆关,也就不够严谨。
-
宏可能会带来运算符优先级的问题,导致程容易出现错。
宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。
\#define MALLOC(num, type)\ (type*)malloc(num sizeof(type))...
//使⽤
MALLOC(10, int);//类型作为参数 //预处理器替换之后:
(int *)malloc(10*sizeof(int));
宏和函数的一个对比:
属性 | #define定义宏 | 函数 |
---|---|---|
代码长度 | 每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的代码长度会大幅度增长 | 函数代码只出现在一个地方;每次使用函数时,都调用那个地方的同一份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,可能会对性能产生一些影响 |
操作优先级 | 函数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则附近操作符的优先级可能会产生不可预料的后果,所以建议在宏写的时候加上括号 | 函数参数只有函数调用时的时序值一次,结果值不涉及操作符。表达式的值能够预知 |
带有副作用的参数 | 宏可能被替换到宏体中的多个位置,如果宏的参数涉及多次计算,带有副作用的参数就可能会产生不预料的结果 | 函数参数只在传参时使用一次,参数易于控制 |
参数类型 | 宏的参数与类型无关,只要函数的参数类型合适,它就可以使用任何参数类型 | 函数的参数与类型相关,如果参数类型不同,就需要不同的函数,即使使用的任务是不同的 |
调试 | 宏是不方便调试的 | 函数可以通过调试 |
递归 | 宏是不可能递归的 | 函数可以递归调用 |
补充:函数和宏之间的抉择
实现的逻辑比较简单,不容易出错时使用宏,反之推荐使用函数。
7. #和##
7.1 #运算符
#
运算符将宏的一个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。
当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10
.
还有一个浮点型变量float f = 5.5f的时候,想打印出:the value of f a is 5.5
.
同时因为每次打印都需要同时改变前面的变量名和后面的值,并且每次打印的变量类型还会发生改变,所以使用函数封装这个语句是比较难以实现的,但是这个逻辑又是比较简单的,所以可以尝试利用宏来封装这个语句。
就可以在预处理时写:
#define PRINT(format, n) printf("the value of "#n " is" format"\n", n);
当我们按照下⾯的⽅式调⽤的时候:
PRINT("%d", a);//当我们以%d的格式打印并把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",时⼀个字符串
PRINT("%f", f);
代码就会被预处理为:
printf("the value of ""a" " is %d\n", a);
printf("the value of ""f" " is %f\n", f);
**注意:**同时C语言中两个或多个字符串天然的可以结合合成一个字符串,虽然上述代码中有多个引号,看似将这几个字符串分隔开来其实在打印的时候将自动将这些字符串结合起来形成一个字符串。
运⾏代码就能在屏幕上打印:
the value of a is 10
the value of a is 5.5000000
7.2 ##运算符
##
可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。 ##
被称为记号粘合。
这样的连接必须产⽣⼀个合法的标识符。否则其结果就是未定义的。
这⾥我们想想,写⼀个函数求2个数的较⼤值的时候,针对不同的数据类型就得写不同的函数。
⽐如:
int int_max(int x, int y)
{return x>y?x:y;
}float float_max(float x, float y)
{return x>yx:y;
}
但是这样写起来太繁琐了,现在我们这样写代码试试:
//宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}
使⽤宏,定义不同函数
GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名 //int_max(int x, int y){ return (x > y ? x : y)}
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名 //float_max(int x, int y){ return (x > y ? x :y)}int main()
{//调⽤函数 int m = int_max(2, 3);printf("%d\n", m);float fm = float_max(3.5f, 4.5f);printf("%f\n", fm);return 0;
}
输出:
3
4.500000
在实际开发过程中##使⽤的很少,很难取出⾮常贴切的例⼦。
8. 命名约定
一般来说函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。平时的习惯是:
- 把宏名全部大写
- 函数名不要全部大写
9. #undef
这条指令用于移除一个宏定义。
#undef NAME
//如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除
10. 命令行定义
许多C的编译器提供了一个能力,允许在命令行中定义符号,用于启动编译过程。
例如:当我们根据同⼀个源⽂件要编译出⼀个程序的不同版本的时候,这个特性有点⽤处。(假定某 个程序中声明了⼀个某个⻓度的数组,如果机器内存有限,我们需要⼀个很⼩的数组,但是另外⼀个 机器内存⼤些,我们需要⼀个数组能够⼤些。)
#include <stdio.h>int main()
{int array [ARRAY_SIZE];int i = 0;for(i = 0; i< ARRAY_SIZE; i ++){array[i] = i;}for(i = 0; i< ARRAY_SIZE; i ++){printf("%d " ,array[i]);}printf("\n" );return 0;
}
编译指令:
//linux 环境演⽰
gcc -D ARRAY_SIZE=10 programe.c//用gcc来编译的时候用-D选项来指定ARRAY_SIZE的值为10,并指定最后生成的可执行文件的文件名是programe.c
11. 条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃(让其不参与编译)是很方便的。
因为我们有条件编译指令。满足条件,参与编译。不满足条件,不参与编译。
比如说:
调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
示例代码:
#include <stdio.h>#define __DEBUG__int main()
{int i = 0;int arr[10] = {0};for(i=0; i<10; i++){arr[i] = i;#ifdef __DEBUG__printf("%d\n", arr[i]);//为了观察数组是否赋值成功,调试性语句。 #endif //__DEBUG__}return 0;
}
常⻅的条件编译指令:
//1.单分支的条件编译
#if 常量表达式//...
#endif
//常量表达式由预处理器求值,如果使用变量仍不编译。
//为真参与编译,为假不参与编译
如:
#define __DEBUG__ 1int main()
{
#if __DEBUG__printf("hehe");
#endif
//条件判断为真,参与编译,在屏幕上打印hehereturn 0;
}//2.多个分⽀的条件编译
#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif
如:
#define M 1
int main()
{
#if M == 1printf("hehe\n");
#elif M == 3printf("haha\n");
#elif M == 4printf("呵呵\m");
#endifreturn 0;
}
//根据分支一条条判断,为真即参与编译,最后在屏幕上打印hehe//3.判断是否被定义
#if defined(symbol)//看symbol有没有被定义,被定义则参与编译
#ifdef symbol#if !defined(symbol)
#ifndef symbol
如:
#define ZHANGSAN 0//真假不重要,只要定义了即可int main()
{
#if defined(ZHANGSAN)printf("zhangsan\n");//前面被定义,故参与编译
#endifreturn 0;
}//4.嵌套指令
#if defined(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"
查找策略:先在源⽂件所在⽬录下查找,如果该头⽂件未找到,编译器就像查找库函数头⽂件⼀样在 标准位置查找头⽂件。
如果找不到就提⽰编译错误。
Linux环境的标准头⽂件的路径:
/usr/include
VS环境的标准头⽂件的路径:、
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include
//这是VS2013的默认路径
注意按照⾃⼰的安装路径去找。
12.1.2 库文件包含
#include <filename.h>
查找头⽂件直接去标准路径下去查找,如果找不到就提⽰编译错误。
这样是不是可以说,对于库⽂件也可以使⽤ “”
的形式包含?
答案是肯定的,可以,但是这样做查找的效率就低些,当然这样也不容易区分是库⽂件还是本地⽂件了。
12.2 嵌套文件包含
我们已经知道, #include 指令可以使另外⼀个⽂件被编译。就像它实际出现于 #include 指令的 地⽅⼀样。
这种替换的⽅式很简单:预处理器先删除这条指令,并⽤包含⽂件的内容替换。
⼀个头⽂件被包含10次,那就实际被编译10次,如果重复包含,对编译的压⼒就⽐较⼤。
test.c
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"int main()
{return 0;
}
test.h
void test();struct Stu{int id;char name[20];
};
如果直接这样写,test.c⽂件中将test.h包含5次,那么test.h⽂件的内容将会被拷⻉5份在test.c中。
如果test.h⽂件⽐较⼤,这样预处理后代码量会剧增。如果⼯程⽐较⼤,有公共使⽤的头⽂件,被⼤家 都能使⽤,⼜不做任何的处理,那么后果真的不堪设想。
如何解决头⽂件被重复引⼊的问题?答案:条件编译。
每个头⽂件的开头写:
#ifndef __TEST_H__
#define __TEST_H__//头⽂件的内容 #endif //__TEST_H__
或者
#pragma once
就可以避免头⽂件的重复引⼊。
注:
推荐《⾼质量C/C++编程指南》中附录的考试试卷(很重要)。
笔试题:
- 头⽂件中的ifndef/define/endif是⼲什么⽤的?
防止一个头文件被多次包含。
- #include<filename.h>和#include"filename.h"有什么区别?
区别主要在查找策略上,前者针对标准库头文件的引入,后者主要针对本地自行创建头文件的引入。
13. 其他预处理指令
#error
#pragma
#line
...
不做介绍,⾃⼰去了解。#pragma pack()在结构体部分介绍。
参考《C语⾔深度解剖》学习
相关文章:
C语言--预处理详解
预处理详解 1. 预定义符号 C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。 __FILE__ //进行编译的源文件__LINE__ //文件当前的行号__DATE__ //文件被编译的日期__TIME__ //文件被编译的时间__STDC__ //如果编译器遵循A…...
不要升级,Flutter Debug 在 iOS 18.4 beta 无法运行,提示 mprotect failed: Permission denied
近期如果有开发者的 iOS 真机升级到 18.4 beta,大概率会发现在 debug 运行时会有 Permission denied 的相关错误提示,其实从 log 可以很直观看出来,就是 Dart VM 在初始化时,对内核文件「解释运行(JIT)」时…...
Kubespray部署企业级高可用K8S指南
目录 前言1 K8S集群节点准备1.1 主机列表1.2 kubespray节点python3及pip3准备1.2.1. 更新系统1.2.2. 安装依赖1.2.3. 下载Python 3.12源码1.2.4. 解压源码包1.2.5. 编译和安装Python1.2.6. 验证安装1.2.7. 设置Python 3.12为默认版本(可选)1.2.8. 安装pi…...
基于zookeeper搭建kafka集群
1、什么是kafka Kafka 是一款开源的分布式流处理平台,最初由 LinkedIn 开发,后由 Apache 基金会维护。它被设计用于高吞吐、可扩展的实时数据管道和流处理场景。Kafka 的核心功能包括发布和订阅消息流、持久化存储数据以及实时处理数据流。其架构基于生…...
Linux操作系统5- 补充知识(可重入函数,volatile关键字,SIGCHLD信号)
上篇文章:Linux操作系统5-进程信号3(信号的捕捉流程,信号集,sigaction)-CSDN博客 本篇Gitee仓库:myLerningCode/l26 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 目录 一. 可重入…...
PyCharm中通过命令行执行`pip`命令下载到哪里了:虚拟环境目录下
PyCharm中通过命令行执行pip命令下载到哪里了:虚拟环境目录下 在PyCharm中通过命令行执行pip命令安装工具包,包的下载位置取决于多种因素 虚拟环境 如果项目使用了虚拟环境(通常是推荐的做法): Windows:虚拟环境通常位于项目目录下的.venv文件夹(默认情况)或你指定…...
JeeWMS graphReportController.do SQL注入漏洞复现(CVE-2025-0392)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…...
部署Joplin私有云服务器postgres版-docker compose
我曾经使用过一段时间 Joplin,官方版本是收费的,而我更倾向于将数据掌握在自己手中。因此,在多次权衡后,我决定自己搭建 Joplin 服务器并进行尝试。 个人搭建的版本与数据库直连,下面是使用 Docker Compose 配置数据库…...
高频 SQL 50 题(基础版)_550. 游戏玩法分析 IV
高频 SQL 50 题(基础版)_550. 游戏玩法分析 IV select IFNULL(round(count(distinct(restult.player_id))/count(distinct(Activity.player_id)),2),0) as fraction from(select Activity.player_id,Activity.event_datefrom Activity join(select play…...
Redis Redis介绍、安装 - Redis客户端
目录 redis是什么,他的应用场景是什么? Redis的一些主要特点和应用场景: redis的官方网站:Redis redis是键值型数据库:(也就是key-value模式)(跟python的字典很像) …...
计算机毕业设计SpringBoot+Vue.js智能无人仓库管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
课程《MIT Introduction to Deep Learning》
在Youtubu上,MIT Introduction to Deep Learning (2024) | 6.S191 共8节课: (1) MIT Introduction to Deep Learning (2024) | 6.S191 (2) MIT 6.S191: Recurrent Neural Networks, Transformers, and Attention (3) MIT 6.S191: Convolutional Neural N…...
Linux ls 命令
Linux ls(英文全拼: list directory contents)命令用于显示指定工作目录下之内容(列出目前工作目录所含的文件及子目录)。 语法 ls [-alrtAFR] [name...] 参数 : -a 显示所有文件及目录 (. 开头的隐藏文件也会列出)-d 只列出目…...
苹果廉价机型 iPhone 16e 影像系统深度解析
【人像拍摄差异】 尽管iPhone 16e支持后期焦点调整功能,但用户无法像iPhone 16系列那样通过点击屏幕实时切换拍摄主体。前置摄像头同样缺失人像深度控制功能,不过TrueTone原彩闪光灯系统在前后摄均有保留。 很多人都高估了 iPhone 的安全性,查…...
SpringBoot项目中读取resource目录下的文件(六种方法)
文章目录 一、先获取绝对路径再读取文件(jar包里会获取不到) 方法一:类加载器的getResource().getPath()获取目录路径方法二:类加载器的getResource().getPath()获取文件路径 二、直接获取文件流(jar包可用) 方法三:Cl…...
人工智能之数学基础:矩阵的范数
本文重点 在前面课程中,我们学习了向量的范数,在矩阵中也有范数,本文来学习一下。矩阵的范数对于分析线性映射函数的特性有重要的作用。 矩阵范数的本质 矩阵范数是一种映射,它将一个矩阵映射到一个非负实数。 矩阵的范数 前面我们学习了向量的范数,只有当满足几个条…...
Vscode通过Roo Cline接入Deepseek
文章目录 背景第一步、安装插件第二步、申请API key第三步、Vscode中配置第四步、Deepseek对话 背景 如何在vscode编译器中使用deepseek,记录下来,方便备查。 第一步、安装插件 在vscode中安装Roo Cline(prev.Roo Client)插件&…...
一周一个Unity小游戏2D反弹球游戏 - 球反弹的方向
前言 本文将实现当球在球板上反弹时,会根据球板移动的方向来给球施加反弹的力,例如当球板往左移动时反弹球,则球应向左上方反弹,若球板往右移动时反弹球,则球应向右上方反弹。 实现球板的反弹方向逻辑 首先给SpringBoard游戏物体添加上2D的刚体,并设置好对应的参数, 锁定…...
大数据学习(52)-MySQL数据库基本操作
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦ᾑ…...
Pico 4 Enterprise(企业版)与Unity的交互-有线串流调试篇
入手了Pico 4 E做VR开发,谁知入了天坑...根据官方文档,尝试了串流助手、企业串流、PICO Developer Center,陷入了各种版本问题、环境问题的陷阱。而且Pico4E的OS自24年12开始就不再更新,头盔中预装的企业串流版本也较低࿰…...
40岁开始学Java:Java中单例模式(Singleton Pattern),适用场景有哪些?
在Java中,单例模式(Singleton Pattern)用于确保一个类只有一个实例,并提供全局访问点。以下是详细的实现方式、适用场景及注意事项: 一、单例模式的实现方式 1. 饿汉式(Eager Initialization) …...
【基于Raft的KV共识算法】-序:Raft概述
本文目录 1.为什么会有Raft?CAP理论 2.Raft基本原理流程为什么要以日志作为中间载体? 3.实现思路任期领导选举日志同步 1.为什么会有Raft? 简单来说就是数据会随着业务和时间的增长,单机不能存的下,这个时候需要以某种…...
windows下玩转vllm:在wsl下安装vllm后续,设置modelscope作为下载源
文章目录 前言所涉及的之前的关键步骤解决模型权重下载网络不通畅的问题vllm和modelscope整合后的bug附录 ImportError: cannot import name _try_login from modelscope.utils.hf_util 全部报错信息前言 之前,咱们说了,由于windows不支持直接部署vllm,所以要么采用wsl,要…...
redis --- 相关基础知识整理
目录 一、基本1、数据结构2、有序集合的编码1. 压缩列表(Ziplist)2. 跳跃列表(SkipList)3. 动态转换机制 二、应用场景三、持久化1、 RDB 持久化2、 AOF 持久化3、 混合持久化(RDB AOF)4、 RDB和AOF的对比…...
基于Rook的Ceph云原生存储部署与实践指南(下)
#作者:任少近 文章目录 6Ceph资源对像管理6.1查看services6.2查看Jobs6.3 查看deployments.apps6.4查看daemonsets.apps6.5查看configmaps6.6查看clusterroles.rbac.authorization.k8s.io6.7查看clusterrolebindings.rbac.authorization.k8s.io6.8通过cephclusters…...
计算机网络---TCP三握四挥
文章目录 TCPTCP 的核心特点TCP 与 UDP 特性对比TCP 标志位 TCP 的三次握手(建立连接)TCP 三次握手概述图解 TCP 三次握手为什么需要三次握手,而不是两次为什么要三次握手,而不是四次三次握手连接阶段,最后一次 ACK 包…...
linux基础知识
Linux版本 内核版和开发版 奇数为开发板 偶数为稳定版 Debian 属于自由开源稳定的linux发行版本,可以由用户进行维护,目前被教育机构、商业公司、非盈利组织和政府机构使用 Red Hat Enterprise Linux(RHEL) 由red hat公司开发的开源linux版本 RHEL服…...
快检查达梦库怎么了
扁鹊的弟弟来了 要求5分钟定位达梦数据库问题 #!/bin/bash## content 实例个数 告警日志 实例状态 用户连接 活动会话 锁 集群状态 服务状态 磁盘空间 cpu mem 侦听及日志 ## scope 单机、DW、DSC Linux 多实例 ## example 将脚本保存为d.sh,用root用执行&#…...
Python可视化大框架的研究与应用
## 摘要 随着数据科学和人工智能的快速发展,数据可视化成为了数据分析中不可或缺的一部分。Python作为一种功能强大且易于学习的编程语言,提供了多种可视化工具和库。本文旨在探讨Python可视化的主要框架,分析其特点、应用场景以及未来发展趋…...
【智能音频新风尚】智能音频眼镜+FPC,打造极致听觉享受!【新立电子】
智能音频眼镜,作为一款将时尚元素与前沿科技精妙融合的智能设备,这种将音频技术与眼镜形态完美结合的可穿戴设备,不仅解放了用户的双手,更为人们提供了一种全新的音频交互体验。新立电子FPC在智能音频眼镜中的应用,为音…...
jeecgboot项目idea启动项目(二)
文章目录 一、IntelliJ IDEA1.安装2.配置maven3.配置jdk 二、IDEA启动项目三、IDEA2024.1.4破解 一、IntelliJ IDEA IntelliJ IDEA是一款由JetBrains开发的集成开发环境(IDE),主要用于Java和Kotlin编程,但也支持多种其他编程语…...
【计算机网络基础】-------计算机网络概念
1.什么是计算机网络 定义: 图解: 2.最简单的计算机网络 其中: 结点可以是计算机、集线器、交换机、路由器等链路可以是有线链路、无线链路 2.1集线器 2.2交换机 3.互连网(internet)与 路由器 路由器 与 家用路由…...
MCAL-存储器驱动
存储器驱动由内部EEPROM驱动、内部Flash驱动、RAM测试和Flash测试四部分组成。 (1)内部EEPROM驱动 内部EEPROM驱动提供初始化服务,以及对内部EEPROM的读、写、擦除等操作。该驱动模块一次只能接受一个任务。这意味着在任何给定的时间点,只能有一个操作被处理 (2)内部F…...
爬虫系列之【数据解析之正则】《二》
目录 前言 一、正则基本使用 1.1 导包 1.2 接口方法 1.3 换行匹配问题 二、实战案例 完整代码 前言 在爬虫工作中,我们主要会遇到两种类型的文本数据: JSON格式数据 HTML文档数据 对于JSON字符串数据,通常使用Python的字典操作进行键…...
【每日学点HarmonyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较
【每日学点HarmnoyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较 1、HarmonyOS 是否存在统一调整全局字体大小的方法? 是否存在统一调整全局字体大小的方法 可以用动态属性,自定义class实现At…...
ORM Bee V2.5.2.x 发布,支持 CQRS; sql 性能分析;更新 MongoDB ORM分片
Bee, 一个具有分片功能的 ORM 框架. Bee Hibernate/MyBatis plus Sharding JDBC Jpa Spring data GraphQL App ORM (Android, 鸿蒙) 小巧玲珑!仅 940K, 还不到 1M, 但却是功能强大! V2.5.2 (2025・LTS 版) 开发中... **2.5.2.1 新年 ** 支持 Mong…...
【CVPR2024】基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复
论文信息 题目: Wavelet-based Fourier Information Interaction with Frequency Diffusion Adjustment for Underwater Image Restoration 基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复 源码:https://github.com/ChenzhaoNju/WF-Diff 论文创新点 基于频…...
《今日AI-编程-人工智能日报》
一、AI编程工具与行业动态 OpenAI推出GPT-4.5“猎户座”研究预览版 OpenAI发布了迄今为止“最大、最有知识”的模型GPT-4.5“猎户座”,面向Pro用户开放,并计划下周向Plus用户开放。该模型在自然对话中展现出情感智能,但在编程性能上不及深度研…...
计算机网络---SYN Blood(洪泛攻击)
文章目录 三次握手过程SYN Flood攻击原理防御措施协议层优化网络层拦截系统配置调整 TCP协议是 TCP/IP 协议栈中一个重要的协议,平时我们使用的浏览器,APP等大多使用 TCP 协议通讯的,可见 TCP 协议在网络中扮演的角色是多么的重要。 TCP 协议…...
DeepSeek教unity------UI元素长按响应
主要功能说明: 长按检测:通过记录指针按下的时间,判断是否达到 longClickTime,从而触发长按事件。状态管理:使用 StateEnum 枚举管理点击项的当前状态(未按下、按下等待长按、长按已触发)。…...
virtualbox安装ubuntu,配置静态ip
一.安装virtualbox和ubuntu 在VirtualBox中安装无界面版Ubuntu(即Ubuntu Server)的步骤如下: 准备工作 下载Ubuntu Server镜像:从Ubuntu官网 https://ubuntu.com/download/server 下载ISO文件。 安装VirtualBox:确保…...
比较Spring AOP和AspectJ
1. 介绍 当前有多个可用的AOP库,这些库必须能够回答许多问题: 它与我现有的或新的应用程序兼容吗?在哪里可以实施AOP?它与我的应用程序集成的速度有多快?性能开销是多少? 在本文中,我们将着眼…...
DeepSeek掘金——DeepSeek R1驱动的PDF机器人
DeepSeek掘金——DeepSeek R1驱动的PDF机器人 本指南将引导你使用DeepSeek R1 + RAG构建一个功能性的PDF聊天机器人。逐步学习如何增强AI检索能力,并创建一个能够高效处理和响应文档查询的智能聊天机器人。 本指南将引导你使用DeepSeek R1 + RAG构建一个功能性的PDF聊天机器人…...
大模型能给舆情分析带来哪些突破?
大模型在舆情分析领域带来了多方面的突破,具体体现在以下几个方面: 1.提升分析精度与效率 大模型通过深度学习和自然语言处理技术,能够高效地处理海量数据,并从中提取关键信息。例如,大模型可以自动识别文本中的情感倾…...
C++实现3D(EasyX)详细教程
一、关于3D 我们看见,这两个三角形是相似的,因此计算很简单 若相对物体的方向是斜的,计算三角函数即可 不会的看代码 二、EasyX简介 initgraph(长,宽) 打开绘图 或initgraph(长,宽…...
Mysql100道高频面试题
一、基础概念 1. 什么是数据库?DBMS的作用是什么? 数据库:是按照数据结构来组织、存储和管理数据的仓库。它允许用户高效地访问和管理数据。 DBMS(数据库管理系统):是一种软件系统,用于创建和…...
TCP长连接与短连接
TCP长连接与短连接 TCP(传输控制协议)中的长连接和短连接是两种不同的连接管理方式,各有优缺点: 短连接 短连接是指客户端与服务器完成一次数据交换后就断开连接。下次需要通信时,再重新建立连接。 特点࿱…...
【ISP】AF自动对焦
自动对焦方案主要有两种: 主动式对焦:通过TOF、双目进行主动测距,然后使用tuning数据进行对焦。 被动式对焦:利用sensor内容算法进行对焦。 被动式对焦有两种主要的方法: 反差对焦:通过前后推拉镜头找到…...
基于Python Django的人脸识别上课考勤系统(附源码,部署)
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
探索Elasticsearch:认识与安装
目录 Elasticsearch的简介 Elasticsearch的定位 安装Elasticsearch 安装Kibana Elasticsearch的简介 Elasticsearch 是一款基于Apache Lucene的开源搜索引擎,在现代数据管理和分析领域占据重要地位。它以其高效的全文搜索、实时数据分析能力和灵活的分布式架构著…...