源码学习初章-基础知识储备

news2024/9/27 5:49:20

文章目录

  • 学前准备
    • 源码地址
    • 引言
    • extern "C"
  • 宏定义
    • 平台宏
      • 跨平台宏
      • vstdio平台禁用警告宏
    • 连接、双层宏定义
    • 函数宏
      • 系统函数宏
      • 自定义函数宏
      • 多语句执行宏do while0
    • 普通宏定义
  • C的一些必备函数知识
    • 回调函数和函数指针
      • 回调函数wireshark-4.0.7源码例子
      • 函数指针wireshark4.0.7源码例子
  • 结构体和关键字
    • 结构体和联合体
      • 结构体 struct
      • 联合体 union
    • 关键字
      • static
      • extern
      • C++关键字 explicit
  • 标志位与位操作
    • & 、 |、<<、>>
    • 标志位(|加标志)(&减/检标志)
  • 代码习惯
    • if else
    • if else break
    • 函数定义
  • 其他内容后续补充


学前准备

源码地址

cJSON库地址
sqlite-github源码地址
sqlite官方网址
wireshark源码

引言

  • 引言参考的是sqlite和wireshark的部分代码,第二篇开始进入cJSON正式篇
  • 第一篇暂时不涉及github的源码,参考的是sqlite官网发布的shell.c sqlite3.h .c等文件进行简单的知识储备
  • 另外由于工作中多是linux环境所以把vstdio卸载了,但是为了在windows下学习sqlite源码所以我采用的是Qt5.14.1 MinGW32进行开发
  • 本文只会使用cpp的new和delete,其他语法将均为c的语法
  • 面向对象只是一种设计模式,如果你愿意,你可以用汇编来实现面向对象

extern “C”

  • 声明:
    这么做的目的是把c作为底层开发库,这样任何一个编程语言都可以调用c写的库了
  • 区别
    1、因为在 C 语言中,默认的函数调用约定是 C 调用约定(C calling convention),参数通过栈传递,由调用者清理栈。
    2、在 C++ 中,默认的函数调用约定是 C++ 调用约定(C++ calling convention),其实质是通过名称修饰(Name Mangling)来支持函数重载,参数传递方式和 C 调用约定类似,但由于函数名被修饰,因此 C++ 编译器能够识别重载的函数
  • 做法
    在头文件中 所有的 函数 结构体 变量 等能想到的所有内容都放在两个 "{}"中
#ifdef __cplusplus
extern "C" {
#endif
void fun1();
void fun2();
static struct Stu{
	int a;
	char b;
}stu{0,0};
int a=10;
#ifdef __cplusplus
}
#endif

宏定义

平台宏

跨平台宏

#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <windows.h>
#elif define(__linux__)
#include <socket.h>
#endif

总结:
- !defined(_CRT_SECURE_NO_WARNINGS)是为了防止C4996报错
- defined(_WIN32)和defined(WIN32)用来判断是否是windows,defined(WIN64)是在win系统基础上判断是不是win64位

vstdio平台禁用警告宏

#if defined(_MSC_VER)
#pragma warning(disable : 4054)// 禁用类型转换警告。此警告提示可能存在的类型转换问题。
#pragma warning(disable : 4055)//禁用类型转换警告。此警告提示可能存在的类型转换问题。
#pragma warning(disable : 4100)//禁用未使用的形参警告。此警告提示声明了但未在函数体内使用的形式参数。
//等
#endif /* defined(_MSC_VER) */

连接、双层宏定义

#include <stdio.h>

// 定义连接运算符宏
#define CONCAT(x, y) x##y

//双层宏定义
/*
 * 双重宏的第一个宏用于接收参数,并进行预处理操作。
 * 第二个宏则负责将经过预处理的参数传递给其他宏或函数,或者用于宏展开后的标识符构造
 * */
// 第一个宏,用于将宏参数转换为字符串常量
#define SHELL_STRINGIFY_(f) #f
// 第二个宏,用于传递参数给第一个宏进行处理
#define SHELL_STRINGIFY(f) SHELL_STRINGIFY_(f)

int main() {
    // 使用连接运算符宏
    int CONCAT(number, 1) = 42; // 等同于 int number1 = 42;
    printf("Value: %d\n", number1);
    // 注意:下面这个例子在预处理阶段将连接运算符宏展开为"Hello",而不是一个新的标识符
    printf("%s\n", "Hello" "World");
    printf("The value is: %s\n", SHELL_STRINGIFY(number1));//使用双层宏定义
    return 0;
}

在这里插入图片描述

函数宏

系统函数宏

将系统函数变成我们自己的宏即可省去后期我们大量调用时的麻烦
当然也可以自己写个函数通过宏实现

# define GETPID (int)GetCurrentProcessId//获取当前进程函数
#include <stdio.h>
#include <windows.h>

// 定义宏,用于获取当前进程ID
#define GETPID (int)GetCurrentProcessId

// 定义宏,用于检查给定的字符是否为空白字符(包括空格、制表符、换行符等)
#define IsSpace(X)  isspace((unsigned char)X)

// 定义宏,用于检查给定的字符是否为十进制数字字符(0-9)
#define IsDigit(X)  isdigit((unsigned char)X)

// 定义宏,用于将给定的字符转换为小写字符
#define ToLower(X)  (char)tolower((unsigned char)X)

// 定义宏,用于将给定的字符转换为大写字符
#define ToUpper(X)  (char)toupper((unsigned char)X)

int main() {
    // 使用宏来获取当前进程ID
    int pid = GETPID();

    // 输出当前进程ID
    printf("Current process ID: %d\n", pid);

    // 另外,我们也可以直接调用 GetCurrentProcessId 函数来获取进程ID
    int pid_direct = GetCurrentProcessId();
    printf("Current process ID (direct call): %d\n", pid_direct);

    // 测试字符处理的宏
    char ch = 'a';

    // 使用 IsSpace 宏来检查字符 ch 是否为空白字符
    if (IsSpace(ch)) {
        printf("The character is a whitespace character.\n");
    } else {
        printf("The character is not a whitespace character.\n");
    }

    // 使用 IsDigit 宏来检查字符 ch 是否为数字字符
    if (IsDigit(ch)) {
        printf("The character is a digit.\n");
    } else {
        printf("The character is not a digit.\n");
    }

    // 使用 ToLower 宏将字符 ch 转换为小写形式,并输出转换后的字符
    printf("The lowercase of the character is: %c\n", ToLower(ch));

    // 使用 ToUpper 宏将字符 ch 转换为大写形式,并输出转换后的字符
    printf("The uppercase of the character is: %c\n", ToUpper(ch));

    return 0;
}

在这里插入图片描述

自定义函数宏

//宏定义自己的函数
//注意显示转换不是必须的,但写上更加直观
#include <iostream>
using namespace std;

#define MIN(x,y) (int)min((int)x, (int)y)
int min(int a,int b) {
    int ret = a<b?a:b;
    cout<<"min is "<<ret<<endl;
    return ret;
}

int main()
{
   cout<<MIN(10,5);

   return 0;
}

在这里插入图片描述

多语句执行宏do while0

# define CONTINUE_PROMPT_RESET \
  do {setLexemeOpen(&dynPrompt,0,0); trackParenLevel(&dynPrompt,0);} while(0)
  • 当有多条语句要执行时需要用{}将函数括起来,而用{}需要用do while循环好处:
    1、使宏的用法更像函数调用,增加了代码的可读性和可维护性
    2、可以避免一些编译器警告,因为使用了多条语句,编译器会认为这是一个复合语句
    3、do-while(0) 循环体会执行一次,因为条件永远为真。这并不会引起运行时额外的开销,因为优化后的编译器会将其优化掉
  • 重点:宏中需要一行写完,如果分行需要用 \ 进行换行
#include <stdio.h>
// 假设这是全局变量,实际情况下可能是其他类型的全局变量
int dynPrompt;

// 假设这是虚拟的函数,实际情况下可能是其他具体的函数
void setLexemeOpen(int* prompt, int arg1, int arg2) {
    // 这里省略函数的具体实现
    dynPrompt = -1;
    printf("setLexemeOpen called with arguments: %d, %d\n", arg1, arg2);
}

void trackParenLevel(int* prompt, int arg) {
    // 这里省略函数的具体实现
    printf("trackParenLevel called with argument: %d\n", arg);
}

// 定义宏
#define CONTINUE_PROMPT_RESET \
    do { \
        setLexemeOpen(&dynPrompt, 0, 0); \
        trackParenLevel(&dynPrompt, 0); \
    } while(0)

int main() {
    printf("Before calling CONTINUE_PROMPT_RESET:\n");
    printf("dynPrompt = %d\n", dynPrompt);

    // 使用宏 CONTINUE_PROMPT_RESET
    CONTINUE_PROMPT_RESET;

    printf("\nAfter calling CONTINUE_PROMPT_RESET:\n");
    printf("dynPrompt = %d\n", dynPrompt);

    return 0;
}

在这里插入图片描述

# define CONTINUE_PROMPT_AWAITS(p,s) \
  if(p && stdin_is_interactive) setLexemeOpen(p, s, 0)
  //这个 if 是条件语句(单个条件语句),所以不用 do while0

普通宏定义

  • 宏代表的是指针
    #define CONTINUE_PROMPT_PSTATE_PTR (&dynPrompt)
  • 宏代表的是变量
    #define CONTINUE_PROMPT_PSTATE_VALUE dynPrompt
  • 代表的是具体的常数
    #define CONTINUE_PROMPT_PSTATE_CONSTANT 42
#include <stdio.h>

// 假设这是全局变量,实际情况下可能是其他类型的全局变量
int dynPrompt = 42;

// 定义三个不同的宏
#define CONTINUE_PROMPT_PSTATE_PTR (&dynPrompt)
#define CONTINUE_PROMPT_PSTATE_VALUE dynPrompt
#define CONTINUE_PROMPT_PSTATE_CONSTANT 42

int main() {
    int *ptr = CONTINUE_PROMPT_PSTATE_PTR; // ptr 指向 dynPrompt 的地址
    int value = CONTINUE_PROMPT_PSTATE_VALUE; // value 的值是 dynPrompt 的值,即 42
    int constant = CONTINUE_PROMPT_PSTATE_CONSTANT; // constant 的值是 42

    printf("dynPrompt: %d\n", dynPrompt);
    printf("Address of dynPrompt: %p\n", &dynPrompt);
    printf("ptr: %p\n", ptr);
    printf("value: %d\n", value);
    printf("constant: %d\n", constant);

    return 0;
}

在这里插入图片描述

C的一些必备函数知识

回调函数和函数指针

#include <iostream>
using namespace std;
//函数指针
void (*funPtr)(int a,int b);
//下面的 max和min会赋值给函数指针
void max(int a,int b){
    int ret = a>b?a:b;
    cout<<"max is "<<ret<<endl;
}
void min(int a,int b) {
    int ret = a<b?a:b;
    cout<<"min is "<<ret<<endl;
}
//回调函数
typedef void (*callBack)(int a,int b);//回调函数比函数指针多了一个typedef
void sameFun(int a, int b , callBack fun){
    fun(a,b);
}
int main()
{
   cout << "Hello World" << endl;
   funPtr = max;
   funPtr(10,5);
   funPtr = min;
   funPtr(10,5);

    sameFun(10,5,max);
    sameFun(10,5,min);
   return 0;
}

在这里插入图片描述

回调函数wireshark-4.0.7源码例子

packet.h:76
typedef int (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *, void *);//回调函数声明

packet.c:3310
/* Register a new dissector by name. */
dissector_handle_t
register_dissector(const char *name, dissector_t dissector, const int proto)
{
	struct dissector_handle *handle;

	handle = new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, NULL, NULL);

	return register_dissector_handle(name, handle);
}

packet-ssh.c:4799
 ssh_handle = register_dissector("ssh", dissect_ssh, proto_ssh);

packet-ssh.c:676
 static int
dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
/*这里面是ssh解析的具体代码,不做展示*/
}

函数指针wireshark4.0.7源码例子

packet-ssh.c:185
truct ssh_flow_data {
    guint   version;

    gchar*  kex;
    int   (*kex_specific_dissector)(guint8 msg_code, tvbuff_t *tvb,
            packet_info *pinfo, int offset, proto_tree *tree,
            struct ssh_flow_data *global_data, guint *seq_num);//函数指针声明

    /* [0] is client's, [1] is server's */
#define CLIENT_PEER_DATA 0
#define SERVER_PEER_DATA 1
/*后续代码略*/
}
//---------------------------------------------------------------------------------
packet-ssh.c:1702
static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data)
{
    const char *kex_name = global_data->kex;

    if (!kex_name) return;

    if (strcmp(kex_name, "diffie-hellman-group-exchange-sha1") == 0 ||
        strcmp(kex_name, "diffie-hellman-group-exchange-sha256") == 0)
    {
        global_data->kex_specific_dissector = ssh_dissect_kex_dh_gex;//函数指针赋值
    }
    /*dh group 和 ecdh 略*/
}
//---------------------------------------------------------------------------------
packet-ssh.c:1361
static int ssh_dissect_kex_dh_gex(guint8 msg_code, tvbuff_t *tvb,
        packet_info *pinfo, int offset, proto_tree *tree,
        struct ssh_flow_data *global_data, guint *seq_num)

结构体和关键字

结构体和联合体

结构体 struct

static struct DynaPrompt {
  char dynamicPrompt[PROMPT_LEN_MAX];
  char acAwait[2];
  int inParenLevel;
  char *zScannerAwaits;
} dynPrompt = { {0}, {0}, 0, 0 };
  • 因为C没有构造函数,不能像cpp一样在构造函数对结构体进行赋初值,因此它赋初值的方法是在结构体定义的尾部赋值

  • 每个成员变量含义:
    dynamicPrompt 数组被初始化为 {0}:即所有元素都是空字符 ‘\0’。
    acAwait 数组被初始化为{0}:即设置为两个空字符 ‘\0’。
    inParenLevel 被初始化为 0:表示括号的层级初始值为 0。
    zScannerAwaits被初始化为 0:它被初始化为 0,即指向空地址。

联合体 union

  • 联合体的所有成员共用同一块内存空间,不同成员在内存中的位置是重叠的。
  • 联合体的大小等于所有成员中占用内存最大的那个成员的大小
  • 在同一时间,只能使用一个成员,存储一个成员的值会覆盖其他成员的值。
#include <stdio.h>
#include <string.h>

union Data {
    int integerData;
    float floatData;
    char stringData[20];
} data;

int main() {
    // 存储整数数据
    data.integerData = 42;
    printf("Integer Data: %d\n", data.integerData);

    // 存储浮点数数据
    data.floatData = 3.14;
    printf("Float Data: %.2f\n", data.floatData);

    // 存储字符串数据
    strcpy(data.stringData, "Hello, Union!");
    printf("String Data: %s\n", data.stringData);

    // 访问整数数据(此时整数数据会被覆盖)
    printf("Integer Data: %d\n", data.integerData);

    return 0;
}

在这里插入图片描述

关键字

  • static和extern的作用是相反的

static

因为源码中有大量的static函数、结构体等。
静态函数的作用是:

  • 函数隐藏在当前源文件中,对其他部分不可见,实现隐藏实现细节的目的
  • 将函数声明为 static 可以限制其作用域,避免与其他文件中的同名函数冲突
  • 这是一种常见的编程技巧,用于实现模块化的代码结构和增强程序的安全性。

extern

  • 当在一个源文件中使用 extern 来声明函数时,它告诉编译器该函数是在另一个源文件中定义的,而不是在当前文件中定义的
  • 通常,这样的声明会放在头文件中,然后在其他源文件中包含该头文件,以便其他源文件可以访问和调用声明的函数。

C++关键字 explicit

  • 这个关键字加在构造函数前,保证代码安全性
class MyClass {
public:
    explicit MyClass(int value) {
        // 构造函数的实现
    }
};
//如果没有explicit关键字那么构造函数可以隐式调用
int num = 42;
MyClass obj = num; // 隐式调用构造函数,将整数转换为 MyClass 类型
//加上explicit关键字必须显式创建对象
int num = 42;
MyClass obj(num); // 显式调用构造函数,将整数转换为 MyClass 类型

标志位与位操作

& 、 |、<<、>>

1000&1010 = 1000
1000|1010 = 1010
1<<8 = 1*2的八次方(10000000)
256>>8 = 256/2的八次方(
10000000>>8)
可以简单地理解为加减法的关系,本处不做具体解释,可以参考网上其他信息

标志位(|加标志)(&减/检标志)

#include <stdio.h>

// 定义标志位的常量
#define FLAG_A (1 << 0) // 00000001
#define FLAG_B (1 << 1) // 00000010
#define FLAG_C (1 << 2) // 00000100

int main() {
    int flags = 0; // 初始标志位为 0

    // 设置标志位
    flags |= FLAG_A; // 将 FLAG_A 设置为 1
    flags |= FLAG_C; // 将 FLAG_C 设置为 1

    // 检查标志位
    if (flags & FLAG_A) {
        printf("标志位 A 已设置\n");
    } else {
        printf("标志位 A 未设置\n");
    }

    if (flags & FLAG_B) {
        printf("标志位 B 已设置\n");
    } else {
        printf("标志位 B 未设置\n");
    }

    if (flags & FLAG_C) {
        printf("标志位 C 已设置\n");
    } else {
        printf("标志位 C 未设置\n");
    }

    return 0;
}

过程

  • flags = 00000000
  • FLAG_A = 00000001
    flags = 00000000 | 00000001 = 00000001
  • FLAG_C = 00000100
    flags = 00000001 | 00000100 = 00000101
  • FLAG_A = 00000001
    flags = 00000101 & 00000001 = 00000001 (非零,表示标志位 A 已设置)
  • FLAG_B = 00000010
    flags = 00000101 & 00000010 = 00000000 (为零,表示标志位 B 未设置)
  • FLAG_C = 00000100
    flags = 00000101 & 00000100 = 00000100 (非零,表示标志位 C 已设置)
  • 这样我们通过 | 加标志 再用 & 检查标志,我们就可以通过3bit的数据获得8种标志位情况
  • 实际上我们不必用&检查标志位,因为8种情况我们都是知道的所以直接 == 0111(0x07) 或 0011(0x03)(等6种情况)即可
    注:各种源码这种标志位过于普遍,本处不再贴此类代码

代码习惯

if else

if( dynPrompt.inParenLevel>9 ){
  shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4);
}else if( dynPrompt.inParenLevel<0 ){
  shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4);
}else{
  shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4);
  dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel);
}

if else break

if( nmb !=0 && noc+nmb <= ncmax ){
          //sss
}else break; 

函数定义

这种函数参数列表是第一次看到
工作中没有遇到过这种写法,但是这种注释确实比较方便,易读性很好
后续会对这种格式进行讨论

static char *shellFakeSchema(
  sqlite3 *db,            /* The database connection containing the vtab */
  const char *zSchema,    /* Schema of the database holding the vtab */
  const char *zName       /* The name of the virtual table */
){
//。。。
}

其他内容后续补充

这个是为了cJSON库源码学习先初步学习的一些知识储备

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/809421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter-基础Widget

Flutter页面-基础Widget 文章目录 Flutter页面-基础WidgetWidgetStateless WidgetStateful WidgetState生命周期 基础widget文本显示TextRichTextDefaultTextStyle 图片显示FlutterLogoIconImageIamge.assetImage.fileImage.networkImage.memory CircleAvatarFadeInImage 按钮R…

视频号私信关注引流脚本实操演示教学,分享几个微信视频号引流推广的方法

大家好&#xff0c;我是小刘互联网思维。最近视频号越来越火&#xff0c;所以很多人或者小团队也都盯上了这个新兴市场。有人选择手动引流&#xff0c;就一定有人想软件引流&#xff0c;有些朋友就私信问我这个软件引流要怎么操作&#xff0c;接下来我就为大家简单讲解视频号脚…

【数据结构】【王道408】——PPT截图与思维导图

自用视频PPT截图 视频网址王道B站链接 23考研 408新增考点&#xff1a; 并查集&#xff0c;红黑树 2023年408真题数据结构篇 408考纲解读 考纲变化 目录 第一章 绪论第二章 线性表顺序表单链表双链表循环链表静态链表差别 第三章 栈 队列 数组栈队列栈的应用数组 第四章 串第五…

RustDesk 1.2 现已发布

RustDesk 1.2 现已发布&#xff0c;此版本采用 Flutter 重写桌面版本&#xff0c;支持 Wayland 被控。 一些值得关注的变化有&#xff1a; 用 Flutter 重写支持 ipv6&#xff08;Beta&#xff09;增加一次性密码QuickSupport &#xff08;Beta&#xff09;硬件编解码器 H264 /…

支持向量机(iris)

代码&#xff1a; import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn import svm import numpy as np# 定义每一列的属性 colnames [sepal-length, sepal-width, petal-length, petal-width, class] # 读取数据 iris pd.read_csv(data\\i…

MicroPython动手做(14)——掌控板之OLED屏幕

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

win10安装vs6行号插件

插件包名&#xff1a;win10 VC6LineNumberAddin 下载包&#xff1a; 链接: https://pan.baidu.com/s/13T-NAxQQDcA_K1hHJQ0vWw?pwdbe3r 提取码: be3r 修改reg为以下&#xff1a; Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\DavidHowe Software\Lie…

想要零起步做跨境电商,可以试试这7个步骤!

近几年&#xff0c;跨境电商行业在不断的高速发展。国家政策的支持&#xff0c;行业的迅猛发展&#xff0c;使得跨境电商成为我国经济发展中的一匹黑马&#xff0c;不仅业务呈爆发式增长&#xff0c;我国跨境电商也逐步实现了“买全球卖全球”的愿望。 想要零起步做跨境电商&a…

linux学习(gbd进程)[5]

gdb set var i n #可设置变量值进程 冯诺依曼结构

LabVIEW使用灰度和边缘检测进行视频滤波

LabVIEW使用灰度和边缘检测进行视频滤波 数字图像处理&#xff08;DIP&#xff09;是真实和连续世界的离散表示。除此之外&#xff0c;这种数字图像在通信、医学、遥感、地震学、工业自动化、机器人、航空航天和教育等领域变得非常重要。计算机技术越来越需要视频图像的数字图…

一文讲解开发中的命名规范

命名规范 好的代码本身就是注释, 所以我们需要统一命名风格。 ​ 在本文中&#xff0c;将从大到小&#xff0c;从外到内&#xff0c;总结Java编程中的命名规范。文中将会涉及到日常工作中常见的命名示例&#xff0c;如包命名&#xff0c;类命名&#xff0c;接口命名&#xff0c…

java+springboot+mysql智慧办公OA管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的智慧办公OA管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;部门管理&#xff1b;职位管理&#xff1b;员工管理…

传输层中一些零碎且易忘的知识点

端口号&#xff1a;共两个字节 不同类型的端口号&#xff1a; 服务端端口号 熟知端口号&#xff1a;0&#xff5e;1023登记端口号&#xff1a;1024&#xff5e;49151 客户端使用端口号&#xff08;短暂/临时端口号&#xff09;&#xff1a;49152&#xff5e;65535 要记得常见应…

Linux之Shell 编程详解(一)

第 1 章 Shell 概述 1&#xff09;Linux 提供的 Shell 解析器有 [atguiguhadoop101 ~]$ cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh2&#xff09;bash 和 sh 的关系 [atguiguhadoop101 bin]$ ll | grep bash -rwxr-xr-x. 1 root root …

EIP-2535 Diamond standard 实用工具分享

前段时间工作对接到了这标准的协议&#xff0c;于是简单介绍下这个标准分享下方便前端er使用的调用工具 一、标准的诞生 在写复杂逻辑的solidity智能合约时&#xff0c;经常会碰到两个问题&#xff0c;升级和合约大小限制。 升级目前有几种proxy模式&#xff0c;通过delegateca…

Minio在windows环境配置https访问

minio启动后&#xff0c;默认访问方式为http&#xff0c;但是有的时候我们的访问场景必须是https&#xff0c;浏览器有的会默认以https进行访问&#xff0c;这个时候就需要我们进行配置上的调整&#xff0c;将minio从http访问升级到https。而查看minio的官方文档&#xff0c;并…

基于Fringe-Projection环形投影技术的人脸三维形状提取算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .................................................................... figure; imshow(Im…

JavaScript高级——ES6基础入门

目录 前言let 和 const块级作用域模板字符串一.模板字符串是什么二.模板字符串的注意事项三. 模板字符串的应用 箭头函数一.箭头函数是什么二.普通函数与箭头函数的转换三.this指向1. 全局作用域中的 this 指向2. 一般函数&#xff08;非箭头函数&#xff09;中的this指向3.箭头…

Android性能优化之SharedPreference卡顿优化

下面的源码都是基于Android api 31 1、SharedPreference使用 val sharePref getPreferences(Context.MODE_PRIVATE) with(sharePref.edit()) { putBoolean("isLogin", true)putInt("age", 18)apply() } val isLogin sharePref.getBoolean("isLogi…

Flink CEP(二) 运行源码解析

通过DemoApp学习一下&#xff0c;CEP的源码执行逻辑。为下一篇实现CEP动态Pattern奠定理论基础。 1. Pattern的定义 Pattern<Tuple3<String, Long, String>,?> pattern Pattern.<Tuple3<String, Long, String>>begin("begin").where(new…