嵌入式C语言:结构体的多态性之结构体中的void*万能指针
目录
一、void*指针在结构体中的应用
二、实现方式
2.1. 定义通用结构体
2.2. 定义具体结构体
2.3. 初始化和使用
三、应用场景
3.1. 内存管理函数
3.2. 泛型数据结构(链表)
3.3. 回调函数和函数指针
3.4. 跨语言调用或API接口(模拟)
4.1. 类型安全问题
4.2. 内存管理问题
4.3. 代码可读性和可维护性问题
4.4. 并发访问问题
4.5. 性能问题
在嵌入式C语言编程中,结构体常常用于数据封装和组织。而在实现多态性(polymorphism)时,一个常见的技巧是使用void*
类型的指针,即“万能指针”。void*
指针可以指向任何类型的数据,使得它成为实现泛型数据结构(如链表、栈、队列等)和函数(如通用排序、查找等)时非常有用的工具。
一、void*
指针在结构体中的应用
在结构体中使用void*
指针可以实现多种类型的数据存储。例如,可以创建一个通用的链表节点结构体,其中包含一个void*
指针来指向任意类型的数据:
struct Node {void* data;struct Node* next;
};
data
成员可以指向任何类型的数据,而next
成员则指向链表中的下一个节点。
二、实现方式
2.1. 定义通用结构体
首先定义一个包含 void*
指针和类型标识的通用结构体,这个结构体可以作为基类来使用。
#include <stdio.h>// 定义一个基结构体
typedef struct {void* data; // 万能指针,指向具体的数据int type; // 类型标识,用于区分不同的数据类型
} GenericStruct;
2.2. 定义具体结构体
接着定义不同类型的具体结构体,这些结构体可以看作是派生类。
// 定义具体结构体 1
typedef struct {int value;
} IntStruct;// 定义具体结构体 2
typedef struct {float value;
} FloatStruct;
2.3. 初始化和使用
在代码中初始化通用结构体,并根据不同的类型进行处理。
// 初始化通用结构体
void initGenericStruct(GenericStruct* gs, void* data, int type) {gs->data = data;gs->type = type;
}// 处理通用结构体
void processGenericStruct(GenericStruct* gs) {switch (gs->type) {case 1: {IntStruct* intData = (IntStruct*)gs->data;printf("Integer value: %d\n", intData->value);break;}case 2: {FloatStruct* floatData = (FloatStruct*)gs->data;printf("Float value: %.2f\n", floatData->value);break;}default:printf("Unknown type\n");break;}
}int main() {IntStruct intObj = {42};FloatStruct floatObj = {3.14f};GenericStruct gs1, gs2;// 初始化通用结构体initGenericStruct(&gs1, &intObj, 1);initGenericStruct(&gs2, &floatObj, 2);// 处理通用结构体processGenericStruct(&gs1);processGenericStruct(&gs2);return 0;
}
三、应用场景
在嵌入式C语言编程中,结构体中的void*
万能指针在实现多态性方面有着广泛的应用场景。
3.1. 内存管理函数
在C语言中,内存管理函数如malloc
、calloc
、realloc
和free
等通常使用void*
指针作为参数或返回值。因为这些函数需要处理任意类型的内存分配和释放,而void*
指针的通用性使得这一点成为可能。通过void*
指针,可以接收和返回任意类型的数据的内存地址,从而实现了内存管理的多态性。
#include <stdio.h>
#include <stdlib.h>int main() {// 定义一个指向整数的指针,用于后续操作数组int *intArray;int initialSize = 3;int newSize = 5;int i;// 使用 malloc 分配初始内存,用于存储 initialSize 个整数intArray = (int *)malloc(initialSize * sizeof(int));if (intArray == NULL) {fprintf(stderr, "内存分配失败,程序退出。\n");return 1;}// 初始化初始分配的内存中的数组元素for (i = 0; i < initialSize; i++) {intArray[i] = i;}// 打印初始数组元素printf("初始数组元素: ");for (i = 0; i < initialSize; i++) {printf("%d ", intArray[i]);}printf("\n");// 使用 realloc 调整内存大小,使其能存储 newSize 个整数intArray = (int *)realloc(intArray, newSize * sizeof(int));if (intArray == NULL) {fprintf(stderr, "内存重新分配失败,程序退出。\n");return 1;}// 初始化新分配的内存中的数组元素for (i = initialSize; i < newSize; i++) {intArray[i] = i;}// 打印调整大小后的数组元素printf("调整大小后的数组元素: ");for (i = 0; i < newSize; i++) {printf("%d ", intArray[i]);}printf("\n");// 使用 free 释放分配的内存free(intArray);return 0;
}
3.2. 泛型数据结构(链表)
在嵌入式系统中,经常需要使用各种数据结构来存储和组织数据。使用void*指针可以实现泛型数据结构,如链表、队列、栈等,这些数据结构可以存储任意类型的数据。例如,在链表节点结构体中使用void*指针来存储数据,这样链表就可以用来存储整数、浮点数、字符串或自定义结构体等多种类型的数据。这种泛型数据结构的实现提高了代码的复用性和灵活性。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct Node {void *data;struct Node *next;
} Node;Node* createNode(size_t dataSize) {Node *newNode = (Node*)malloc(sizeof(Node));if (!newNode) {perror("Memory allocation failed for new node");exit(EXIT_FAILURE);}newNode->data = malloc(dataSize);if (!newNode->data) {perror("Memory allocation failed for node data");free(newNode);exit(EXIT_FAILURE);}newNode->next = NULL;return newNode;
}void freeNode(Node *node, size_t dataSize) {if (node) {free(node->data);free(node);}
}// 示例:添加整数节点并打印链表
void appendIntNode(Node **head, int value) {Node *newNode = createNode(sizeof(int));*(int*)newNode->data = value;if (*head == NULL) {*head = newNode;} else {Node *temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;}
}void printIntList(Node *head) {Node *temp = head;while (temp != NULL) {printf("%d -> ", *(int*)temp->data);temp = temp->next;}printf("NULL\n");
}int main() {Node *head = NULL;appendIntNode(&head, 10);appendIntNode(&head, 20);appendIntNode(&head, 30);printIntList(head);Node *temp;while (head != NULL) {temp = head;head = head->next;freeNode(temp, sizeof(int));}return 0;
}
3.3. 回调函数和函数指针
在嵌入式编程中,回调函数和函数指针常用于事件处理、异步操作等场景。当回调函数的参数类型或返回值类型不确定时,可以使用void*指针来传递额外的数据。这样,回调函数就可以接收任意类型的数据作为参数,从而实现了回调函数的多态性。例如,在定时器回调函数中,可以使用void*指针来传递指向用户自定义数据结构的指针,以便在回调函数中处理这些数据。
#include <stdio.h>// 回调函数类型定义
typedef void (*Callback)(void*);// 示例回调函数
void myCallback(void *data) {int *value = (int*)data;printf("Callback received value: %d\n", *value);
}// 触发回调的函数
void triggerCallback(Callback cb, void *data) {cb(data);
}int main() {int value = 42;triggerCallback(myCallback, (void*)&value);return 0;
}
3.4. 跨语言调用或API接口(模拟)
在真实的跨语言调用场景中,通常会使用更复杂的机制(如FFI、JNI等)。但以下示例模拟了如何使用void*
指针在C语言中模拟跨语言接口。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 假设这是从另一种语言传入的结构体
typedef struct ForeignStruct {void *data;size_t dataSize;
} ForeignStruct;// 处理传入结构体的函数
void processForeignStruct(ForeignStruct *fs) {if (fs->dataSize == sizeof(int)) {int *value = (int*)fs->data;printf("Processed value from foreign struct: %d\n", *value);} else {printf("Unsupported data size in foreign struct\n");}
}int main() {// 模拟从另一种语言传入的数据int foreignValue = 99;ForeignStruct fs;fs.data = &foreignValue;fs.dataSize = sizeof(int);// 处理传入的结构体processForeignStruct(&fs);return 0;
}
四、使用void*
指针的注意事项
4.1. 类型安全问题
强制类型转换风险:
- 在使用
void*
指针时,常常需要进行强制类型转换。如果类型转换错误,会导致未定义行为。例如,将一个指向int
类型的void*
指针错误地转换为float*
指针并进行操作,可能会读取或写入错误的数据。
int num = 10;
void* ptr = #
float* floatPtr = (float*)ptr; // 错误的类型转换
printf("%f\n", *floatPtr); // 可能输出错误结果
- 解决方案:在进行类型转换前,应确保类型的正确性。可以通过额外的类型标识字段来判断,例如在结构体中添加一个
type
字段,根据该字段的值进行正确的类型转换。
缺乏编译时检查
void*
指针会绕过 C 语言的类型系统,编译器无法在编译时检查指针操作的类型是否匹配。可能导致在运行时才发现类型不匹配的错误,增加调试难度。- 解决方案:编写详细的注释和文档,明确指针的使用规则和预期类型。同时,在代码中添加适当的运行时检查,例如在函数入口处检查指针类型是否正确。
4.2. 内存管理问题
悬空指针:如果 void*
指针指向的内存被释放后,仍然使用该指针,就会形成悬空指针。使用悬空指针会导致未定义行为,可能会破坏其他数据或引发程序崩溃。
int* intPtr = (int*)malloc(sizeof(int));
void* voidPtr = intPtr;
free(intPtr);
// 此时 voidPtr 成为悬空指针
// *voidPtr = 20; // 错误操作
- 解决方案:在释放内存后,及时将指针置为
NULL
,避免误操作。例如:
int* intPtr = (int*)malloc(sizeof(int));
void* voidPtr = intPtr;
free(intPtr);
intPtr = NULL;
voidPtr = NULL;
内存泄漏
- 如果使用
void*
指针分配了内存,但没有正确释放,会导致内存泄漏。特别是在复杂的程序中,多个void*
指针指向同一块内存时,容易出现重复释放或未释放的情况。 - 解决方案:建立清晰的内存管理策略,确保每一块分配的内存都有对应的释放操作。可以使用引用计数等技术来管理内存的生命周期。
4.3. 代码可读性和可维护性问题
- 代码复杂度增加
- 使用
void*
指针会使代码变得复杂,尤其是在处理多个不同类型的数据时。过多的强制类型转换和类型判断会让代码难以理解和维护。 - 解决方案:将与
void*
指针相关的操作封装成函数,减少代码中的重复和复杂性。同时,使用有意义的变量名和注释,提高代码的可读性。
- 使用
- 可移植性问题
- 不同的编译器和平台对
void*
指针的处理可能存在差异,特别是在指针大小和对齐方式上。可能导致代码在不同平台上的行为不一致。 - 解决方案:遵循标准 C 语言规范,避免依赖特定平台的特性。在编写代码时,进行充分的测试,确保代码在不同平台上的可移植性。
- 不同的编译器和平台对
4.4. 并发访问问题
- 如果多个线程同时访问和操作
void*
指针指向的内存,可能会导致数据竞争和不一致的问题。例如,一个线程正在释放内存,而另一个线程还在使用该指针。 - 解决方案:使用同步机制,如互斥锁、信号量等,确保在同一时间只有一个线程可以访问和操作
void*
指针指向的内存。
4.5. 性能问题
- 使用
void*
指针进行类型转换和类型判断会带来额外的开销,尤其是在频繁进行这些操作时。这可能会影响程序的性能。 - 解决方案:在性能敏感的场景中,尽量减少
void*
指针的使用,或者对频繁使用的操作进行优化。例如,可以使用函数指针数组来避免类型判断和强制类型转换。
综上所述,虽然在嵌入式C语言中使用void*
指针作为结构体中的“万能指针”可以实现多态性,但同时也需要仔细考虑和管理与之相关的各种风险和问题。
相关文章:
嵌入式C语言:结构体的多态性之结构体中的void*万能指针
目录 一、void*指针在结构体中的应用 二、实现方式 2.1. 定义通用结构体 2.2. 定义具体结构体 2.3. 初始化和使用 三、应用场景 3.1. 内存管理函数 3.2. 泛型数据结构(链表) 3.3. 回调函数和函数指针 3.4. 跨语言调用或API接口(模拟…...
重构进行时:一秒告别 !=null 判空
重构进行时:一秒告别 !null 判空 空指针异常(NullPointerException)是Java开发中常见的错误之一。 许多开发者在遇到空指针问题时,往往会习惯性地使用! null来进行判断。 然而,当代码中频繁出现这种判断时ÿ…...
React 中hooks之useSyncExternalStore使用总结
1. 基本概念 useSyncExternalStore 是 React 18 引入的一个 Hook,用于订阅外部数据源,确保在并发渲染下数据的一致性。它主要用于: 订阅浏览器 API(如 window.width)订阅第三方状态管理库订阅任何外部数据源 1.1 基…...
Semaphore 与 线程池 Executor 有什么区别?
前言:笔者在看Semaphone时 突然脑子宕机,啥啥分不清 Semaphore 和 Executor 的作用,故再次记录。 一、什么是Semaphore? Semaphore 是 Java 并发编程(JUC)中一个重要的同步工具,它的作用是 控…...
Rust:高性能与安全并行的编程语言
引言 在现代编程世界里,开发者面临的最大挑战之一就是如何平衡性能与安全性。在许多情况下,C/C这样的系统级编程语言虽然性能强大,但其内存管理的复杂性导致了各种安全漏洞。为了解决这些问题,Rust 作为一种新的系统级编程语言进入…...
论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(六)(完结)
Understanding Diffusion Models: A Unified Perspective(六)(完结) 文章概括指导(Guidance)分类器指导无分类器引导(Classifier-Free Guidance) 总结 文章概括 引用: …...
Redis --- 分布式锁的使用
我们在上篇博客高并发处理 --- 超卖问题一人一单解决方案讲述了两种锁解决业务的使用方法,但是这样不能让锁跨JVM也就是跨进程去使用,只能适用在单体项目中如下图: 为了解决这种场景,我们就需要用一个锁监视器对全部集群进行监视…...
电脑怎么格式化?格式化详细步骤
格式化是我们在日常使用电脑时可能会用到的一种操作,无论是清理磁盘空间、安装新系统,还是解决磁盘读写错误,都可能需要格式化。不过,对于一些不熟悉电脑操作的用户来说,格式化听起来可能有些复杂。其实,只…...
TikTok广告投放优化策略:提升ROI的核心技巧
在短许多品牌和商家纷纷投入广告营销,争夺这片潜力巨大的市场。然而,在激烈的竞争环境中,如何精准有效地投放广告,优化广告效果,实现更高的投资回报率(ROI)成为了广告主关注的核心。 一. 精准受…...
视觉语言模型 (VLMs):跨模态智能的探索
文章目录 一. VLMs 的重要性与挑战:连接视觉与语言的桥梁 🌉二. VLMs 的核心训练范式:四种主流策略 🗺️1. 对比训练 (Contrastive Training):拉近正例,推远负例 ⚖️2. 掩码方法 (Masking):重构…...
第05章 08 绘制脑部体绘制图的阈值等值面
绘制脑部体绘制图的阈值等值面,例如肌肉和头骨骼,需要对医学图像数据进行阈值处理,并使用体绘制技术来可视化这些结构。以下是一个基于VTK/C的示例代码,展示如何读取DICOM图像数据,应用阈值过滤器来提取特定组织&#…...
类和对象(4)——多态:方法重写与动态绑定、向上转型和向下转型、多态的实现条件
目录 1. 向上转型和向下转型 1.1 向上转型 1.2 向下转型 1.3 instanceof关键字 2. 重写(overidde) 2.1 方法重写的规则 2.1.1 基础规则 2.1.2 深层规则 2.2 三种不能重写的方法 final修饰 private修饰 static修饰 3. 动态绑定 3.1 动态绑…...
动态规划<九>两个数组的dp
目录 引例 LeetCode经典OJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 引例 OJ传送门LeetCode<1143>最长公共子序列 画图分析: 使用动态规划解决 1.状态表示 ------经验题目要求 经验为选取第一个字符串的[0,i]区间以及第二个字…...
Go:基于Go实现一个压测工具
文章目录 写在前面整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理 客户端模块Http客户端处理Grpc客户端处理Websocket客户端处理 连接处理模块GrpcHttp 统计数据模块统计原理实现过程 写在前面 本篇主要是基于Go来实现一个压测的工具,关于压测的内…...
2025年数学建模美赛 A题分析(2)楼梯使用频率数学模型
2025年数学建模美赛 A题分析(1)Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析(2)楼梯磨损分析模型 2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型 2025年数学建模美赛 A题分…...
在Ubuntu上用Llama Factory命令行微调Qwen2.5的简单过程
半年多之前写过一个教程:在Windows上用Llama Factory微调Llama 3的基本操作_llama-factory windows-CSDN博客 如果用命令行做的话,前面的步骤可以参考上面这个博客。安装好环境后, 用自我认知数据集微调Lora模块:data/identity.j…...
虹科分享 | 汽车NVH小课堂之听音辨故障
随着车主开始关注汽车抖动异响问题,如何根据故障现象快速诊断异响来源,成了汽修人的必修课。 一个比较常用的方法就是靠“听”——“听音辨故障”。那今天,虹科Pico也整理了几个不同类型的异响声音,一起来听听看你能答对几个吧 汽…...
RoboVLM——通用机器人策略的VLA设计哲学:如何选择骨干网络、如何构建VLA架构、何时添加跨本体数据
前言 本博客内解读不少VLA模型了,包括π0等,且如此文的开头所说 前两天又重点看了下openvla,和cogact,发现 目前cogACT把openvla的动作预测换成了dit,在模型架构层面上,逼近了π0那为了进一步逼近&#…...
【SpringBoot教程】Spring Boot + MySQL + HikariCP 连接池整合教程
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 在前面一篇文章中毛毛张介绍了SpringBoot中数据源与数据库连接池相关概念,今天毛毛张要分享的是关于SpringBoot整合HicariCP连接池相关知识点以及底层源码…...
0.91英寸OLED显示屏一种具有小尺寸、高分辨率、低功耗特性的显示器件
0.91英寸OLED显示屏是一种具有小尺寸、高分辨率、低功耗特性的显示器件。以下是对0.91英寸OLED显示屏的详细介绍: 一、基本参数 尺寸:0.91英寸分辨率:通常为128x32像素,意味着显示屏上有128列和32行的像素点,总共409…...
【insert函数】
在 C 中,std::string::insert 是一个功能强大的成员函数,用于在字符串的指定位置插入内容。它有多个重载版本,支持插入 字符、字符串、子字符串 等。以下是 insert 所有相关函数的详细介绍: 1. 插入字符串 函数签名: …...
Python 如何进行文本匹配:difflib| python 小知识
Python 如何进行文本匹配:difflib| python 小知识 difflib是Python标准库中的一个工具,用于比较和处理文本差异。它提供了一组用于比较和处理文本差异的功能,可以用于比较字符串、文件等。本文将详细介绍difflib模块的用法和实现细节&#x…...
MySQL误删数据怎么办?
文章目录 1. 从备份恢复数据2. 通过二进制日志恢复数据3. 使用数据恢复工具4. 利用事务回滚恢复数据5. 预防误删数据的策略总结 在使用MySQL进行数据管理时,误删数据是一个常见且具有高风险的操作。无论是因为操作失误、系统故障,还是不小心执行了删除命…...
可以称之为“yyds”的物联网开源框架有哪几个?
有了物联网的发展,我们的生活似乎也变得更加“鲜活”、有趣、便捷,包具有科技感的。在物联网(IoT)领域中,也有许多优秀的开源框架支持设备连接、数据处理、云服务等,成为被用户们广泛认可的存在。以下给大家…...
为AI聊天工具添加一个知识系统 之74 详细设计之15 正则表达式 之2
本文要点 要点 本项目(为AI聊天工具添加一个知识系统)中的正则表达式。 正则表达式的三“比”。正则表达式被 一、排比为三种符号(元符号-圈号,特殊符号-引号,普通符号-括号) 引号<<a线性回归bo…...
Java 注解与元数据
Java学习资料 Java学习资料 Java学习资料 一、引言 在 Java 编程中,注解(Annotation)和元数据(Metadata)是两个重要的概念。注解为程序提供了一种在代码中嵌入额外信息的方式,这些额外信息就是元数据。元…...
【橘子Kibana】Kibana的分析能力Analytics简易分析
一、kibana是啥,能干嘛 我们经常会用es来实现一些关于检索,关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI,你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…...
度小满前端面试题及参考答案
<form>标签使用过哪些 tag? <form>标签中常使用的标签有很多。 <input>:这是最常用的标签之一,用于创建各种类型的输入字段,如文本框、密码框、单选按钮、复选框、文件上传框等。通过设置type属性来指定输入类型,例如type="text"创建文本输入…...
Padas进行MongoDB数据库CRUD
在数据处理的领域,MongoDB作为一款NoSQL数据库,以其灵活的文档存储结构和高扩展性广泛应用于大规模数据处理场景。Pandas作为Python的核心数据处理库,能够高效处理结构化数据。在MongoDB中,数据以JSON格式存储,这与Pandas的DataFrame结构可以很方便地互相转换。通过这篇教…...
LQ1052 Fibonacci斐波那契数列
题目描述 Fibonacci斐波那契数列也称为兔子数列,它的递推公式为:FnFn-1Fn-2,其中F1F21。 当n比较大时,Fn也非常大,现在小蓝想知道,Fn除以10007的余数是多少,请你编程告诉她。 输入 输入包含一…...
华硕笔记本装win10哪个版本好用分析_华硕笔记本装win10专业版图文教程
华硕笔记本装win10哪个版本好用?华硕笔记本还是建议安装win10专业版。Win分为多个版本,其中家庭版(Home)和专业版(Pro)是用户选择最多的两个版本。win10专业版在功能以及安全性方面有着明显的优势ÿ…...
编译器gcc/g++ --【Linux基础开发工具】
文章目录 一、背景知识二、gcc编译选项1、预处理(进行宏替换)2、编译(生成汇编)3、汇编(生成机器可识别代码)4、链接(生成可执行文件或库文件) 三、动态链接和静态链接四、静态库和动态库1、动静态库2、编译…...
八股文 (一)
文章目录 项目地址一、前端1.1 大文件上传,预览1.2 首页性能优化1.2 流量染色,灰度发布1.3 Websock心跳机制,大数据实时数据优化1.4 Gpu 加速 fps优化1.5 echarts包大小优化和组件封装1.6 前端监控系统1.7 超大虚拟列表卡顿1. 实现2. 相关问题(1) 什么是虚拟化列表,为什么要…...
c语言无符号的变量不能和有符号的直接比较,或者使用移项解决符号问题
使用移项解决问题,简单来说就是无符号运行不要有减号,使用移项后的加号代替 if(uEventDirLimitSize > uEventAndNormalDirSize) {if((uEventDirLimitSize - uEventAndNormalDirSize) > pStConfig->stParam.stUserParam.uEventRemain){return O…...
安卓日常问题杂谈(一)
背景 关于安卓开发中,有很多奇奇怪怪的问题,有时候这个控件闪一下,有时候这个页面移动一下,这些对于快速开发中,去查询,都是很耗费时间的,因此,本系列文章,旨在记录安卓…...
电力晶体管(GTR)全控性器件
电力晶体管(Giant Transistor,GTR)是一种全控性器件,以下是关于它的详细介绍:(模电普通晶体管三极管进行对比学习) 基本概念 GTR是一种耐高电压、大电流的双极结型晶体管(BJT&am…...
【美】Day 1 CPT申请步骤及信息获取指南(Day1 CPT)
参考文章:【美】境外申请Day 1 CPT完整流程(境外Day 1 CPT) 文章目录 **一、申请前准备:了解Day 1 CPT基本要求****二、选择Day 1 CPT学校****1. 搜索学校****2. 筛选标准** **三、申请流程****1. 提交学校申请****2. 转SEVIS记录…...
梯度下降优化算法-动量法
1. 动量法的数学原理 1.1 标准梯度下降回顾 在标准梯度下降中,参数的更新公式为: θ t 1 θ t − η ⋅ ∇ θ J ( θ t ) \theta_{t1} \theta_t - \eta \cdot \nabla_\theta J(\theta_t) θt1θt−η⋅∇θJ(θt) 其中: θ t …...
游戏引擎介绍:Game Engine
简介 定义:软件框架,一系列为开发游戏的工具的集合 可协作创意生产工具,复杂性艺术,注重realtime实时 目的 为艺术家,设计师,程序员设计工具链 游戏引擎开发参考书 推荐:Game Engine Archite…...
zookeeper-3.8.3-基于ACL的访问控制
ZooKeeper基于ACL的访问控制 ZooKeeper 用ACL控制对znode的访问,类似UNIX文件权限,但无znode所有者概念,ACL指定ID及对应权限,且仅作用于特定znode,不递归。 ZooKeeper支持可插拔认证方案,ID格式为scheme…...
ResNeSt: Split-Attention Networks 参考论文
参考文献 [1] Tensorflow Efficientnet. https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet. Accessed: 2020-03-04. 中文翻译:[1] TensorFlow EfficientNet. https://github.com/tensorflow/tpu/tree/master/models/official/efficien…...
正反转电路梯形图
1、正转联锁控制。按下正转按钮SB1→梯形图程序中的正转触点X000闭合→线圈Y000得电→Y000自锁触点闭合,Y000联锁触点断开,Y0端子与COM端子间的内部硬触点闭合→Y000自锁触点闭合,使线圈Y000在X000触点断开后仍可得电。 Y000联锁触点断开&…...
【数据结构】空间复杂度
目录 一、引入空间复杂度的原因 二、空间复杂度的分析 ❥ 2.1 程序运行时内存大小 ~ 程序本身大小 ❥ 2.2 程序运行时内存大小 ~ 算法运行时内存大小 ❥ 2.3 算法运行时内存大小 ❥ 2.4 不考虑算法全部运行空间的原因 三、空间复杂度 ❥ 3.1空间复杂度的定义 ❥ 3.2 空…...
系统学英语 — 句法 — 复合句
目录 文章目录 目录复合句型主语从句宾语从句表语从句定语从句状语从句同位语从句 复合句型 复合句型,即:从句。在英语中,除了谓语之外的所有句子成分都可以使用从句来充当。 主语从句 充当主语的句子,通常位于谓语之前&#x…...
SQL server 数据库使用整理
标题:SQL server 数据库使用整理 1.字符串表名多次查询 2.读取SQL中Json字段中的值:JSON_VALUE(最新版本支持,属性名大小写敏感) 1.字符串表名多次查询 SELECT ROW_NUMBER() OVER (ORDER BY value ASC) rowid,value…...
*胡闹厨房*
前期准备 详细教程 一、创建项目 1、选择Universal 3D,创建项目 2、删除预制文件Readme:点击Remove Readme Assets,弹出框上点击Proceed 3、Edit-Project Setting-Quality,只保留High Fidelity 4、打开 Assets-Settings ,保留URP-HighFidelity-Renderer 和 URP-High…...
.NET 8 项目 Docker 方式部署到 Linux 系统详细操作步骤
本文将详细介绍如何将一个 .NET 8 项目通过 Docker 部署到 Linux 系统中。以下步骤包括从项目的创建、Dockerfile 的编写、镜像构建、到最后在 Linux 上的容器运行。 1. 环境准备 在开始之前,请确保你已经具备以下环境: Linux 系统(如 Ubu…...
状态码对照表
别瞎自定义状态码了 1xx:信息性状态码 状态码名称使用场景100Continue客户端应继续请求,等待后续响应。101Switching Protocols服务器根据客户端的请求切换协议。102Processing服务器正在处理请求,但尚未完成。103Early Hints提供给客户端的…...
【愚公系列】《循序渐进Vue.js 3.x前端开发实践》027-组件的高级配置和嵌套
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…...
Autosar-Os是怎么运行的?(多核系统运行)
写在前面: 入行一段时间了,基于个人理解整理一些东西,如有错误,欢迎各位大佬评论区指正!!! 目录 1.Autosar多核操作系统 1.1多核启动过程 1.2多核运行过程 1.2.1核间任务同步 1.2.2Counte…...