嵌入式的C/C++:深入理解 static、const 与 volatile 的用法与特点
目录
一、static
1、static 修饰局部变量
2、 static 修饰全局变量
3、static 修饰函数
4、static 修饰类成员
5、小结
二、const
1、const 修饰普通变量
2、const 修饰指针
3、const 修饰函数参数
4. const 修饰函数返回值
5. const 修饰类成员
6. const 与 #define 的比较
7. 小结
三、 volatile
1、volatile 的作用
2、volatile 的典型应用场景
3、volatile 的特性与限制
4、volatile 的用法
5、小结
在嵌入式的C/C++ 编程中,关键字不仅仅是语法结构的一部分,更是语言核心特性的体现。static
、const
和 volatile
是三个常见且重要的关键字,广泛应用于变量管理、优化控制、代码安全性和硬件编程等领域。然而,很多开发者在使用它们时,往往只了解表面作用,而忽视了深入理解可能带来的性能优化和代码维护收益。本篇博客将通过细致的分类讲解和实用的示例,带你全面掌握这三个关键字的用法、特性和应用场景。
一、static
static
关键字有多种用途。在函数内部声明的变量前使用 static
关键字,可以让该变量在整个程序运行期间都保持其值,而不是在每次调用函数时重新初始化。对于全局变量或函数,static
可以限制它们的作用域到声明它们的文件内,即其他文件无法访问这些变量或函数。
1、static
修饰局部变量
作用:将局部变量的 生命周期 扩展为整个程序的运行期间,但 作用域 仍局限于函数内部
特点:初始化只会发生一次。再次调用函数时,保留变量上一次的值。
示例:
#include <stdio.h>
void counter() {static int count = 0; // 静态局部变量,初始化只执行一次count++;printf("Count: %d\n", count);
}int main() {counter(); // 输出:Count: 1counter(); // 输出:Count: 2counter(); // 输出:Count: 3return 0;
}
分析:
count
是静态局部变量,第一次调用时初始化为 0。- 每次调用
counter
函数后,count
的值都会被保留,而不是销毁。 - 如果没有
static
,count
每次调用都会重新初始化为 0。
2、 static
修饰全局变量
作用:将全局变量的 作用域 限制在当前文件中,使得其他文件无法直接访问该变量。
特点:全局变量默认具有整个程序可见性,但加上 static
后,仅对声明它的文件可见。有助于模块化和避免命名冲突。
示例:
// file1.c
#include <stdio.h>
static int global_var = 100; // 静态全局变量,仅限于本文件void display() {printf("global_var: %d\n", global_var);
}// file2.c
#include <stdio.h>
extern int global_var; // 错误!无法访问 file1.c 中的静态全局变量int main() {display(); // 只能通过函数间接访问return 0;
}
分析:
global_var
是静态全局变量,仅file1.c
可访问,file2.c
无法通过extern
引用。- 模块化设计中,通过隐藏不必要的全局变量,减少模块间的耦合。
3、static
修饰函数
作用:将函数的作用域限制在当前文件中,避免外部文件调用该函数,起到“私有化”的作用。
特点:函数默认具有外部可见性,加上 static
后仅对当前文件可见。有助于避免命名冲突。
示例:
// file1.c
#include <stdio.h>
static void privateFunction() {printf("This is a static function.\n");
}void publicFunction() {privateFunction(); // 内部可以正常调用
}// file2.c
extern void privateFunction(); // 错误!无法访问 file1.c 中的静态函数int main() {publicFunction(); // 通过非静态函数间接调用return 0;
}
分析:
privateFunction
是静态函数,仅file1.c
内部可调用,file2.c
无法通过extern
声明使用。- 这种机制可以防止外部文件误调用函数,起到保护作用。
4、static
修饰类成员
4.1 静态成员变量
特点:属于整个类而非某个对象。在所有对象中共享,仅在程序中初始化一次。
示例:
#include <iostream>
class MyClass {
public:static int count; // 静态成员变量MyClass() { count++; }
};int MyClass::count = 0; // 静态成员变量初始化int main() {MyClass obj1, obj2, obj3;std::cout << "Object count: " << MyClass::count << std::endl; // 输出:3return 0;
}
4.2 静态成员函数
特点:不能访问非静态成员(因为没有对象实例)。可通过类名直接调用,而无需实例化对象。
示例:
#include <iostream>
class MyClass {
public:static void display() {std::cout << "This is a static member function." << std::endl;}
};int main() {MyClass::display(); // 静态成员函数直接通过类名调用return 0;
}
5、小结
static
关键字在模块化、性能优化和作用域管理中起到非常重要的作用。
二、const
const
关键字用于指定一个对象是常量,即它的值不能通过普通的赋值操作来改变。它可以应用于变量、指针、函数参数等。用于定义不可修改的值或具有只读属性的变量。它在程序设计中用于增强代码的安全性和可维护性。
1、const
修饰普通变量
作用:定义一个只读的变量,不能对其赋新值。
特点:变量的值在程序中固定。编译器会在尝试修改 const
变量时报错。
示例:
#include <stdio.h>
int main() {const int x = 10; // 定义只读变量printf("x = %d\n", x);// x = 20; // 错误:不能修改 const 变量return 0;
}
注意:const
修饰的变量必须初始化,否则会报错
2、const
修饰指针
在指针的定义中,const
的位置决定了指针的只读属性是指针本身还是指针指向的值。
2.1 指向的值是只读的
const int *p = &x; // 或 int const *p = &x;
含义:指针指向的值不能修改,但指针本身可以改变指向的地址。
示例:
#include <stdio.h>
int main() {int x = 10, y = 20;const int *p = &x; // 指针指向的值不可修改// *p = 15; // 错误:不能修改 p 指向的值p = &y; // 合法:可以修改 p 的指向printf("p points to: %d\n", *p);return 0;
}
2.2 指针本身是只读的
int * const p = &x;
含义:指针本身不能修改指向的地址,但指针指向的值可以改变。
示例:
#include <stdio.h>
int main() {int x = 10;int *const p = &x; // 指针本身不可修改*p = 20; // 合法:可以修改 p 指向的值// p = &y; // 错误:不能改变指针的指向printf("x = %d\n", *p);return 0;
}
2.3 指针本身和指向的值都是只读的
const int * const p = &x;
含义:指针本身和指向的值都不可修改。
3、const
修饰函数参数
作用:保护函数的输入参数,防止在函数内部被修改。
应用场景:适用于传入参数的值不应被修改的情况(例如输入只读配置、避免意外修改等)。
3.1 修饰值传递参数
void func(const int x) {// x = 20; // 错误:x 是只读的printf("x = %d\n", x);
}
int main() {func(10);return 0;
}
3.2 修饰指针参数
如果函数需要读取指针指向的值,但不能修改该值:
void display(const int *p) {// *p = 20; // 错误:不能修改 p 指向的值printf("Value: %d\n", *p);
}
如果函数不能修改指针本身的地址:
void display(int * const p) {// p = &y; // 错误:不能修改指针 p 本身的地址*p = 20; // 合法:可以修改 p 指向的值
}
4. const
修饰函数返回值
作用:防止函数返回值被修改。
4.1 修饰返回普通值
const int getValue() {return 10;
}
int main() {const int x = getValue();// x = 20; // 错误:不能修改 x 的值return 0;
}
4.2 修饰返回指针
如果函数返回一个指针,但指针指向的值不可修改:
const int* getPointer() {static int x = 10;return &x;
}
int main() {const int *p = getPointer();// *p = 20; // 错误:不能修改 p 指向的值return 0;
}
5. const
修饰类成员
5.1 修饰类成员变量
作用:类的成员变量定义为只读,必须在构造函数初始化列表中初始化。
#include <iostream>
class MyClass {
public:const int value; // const 成员变量MyClass(int v) : value(v) {} // 必须在构造函数初始化列表中初始化
};int main() {MyClass obj(10);// obj.value = 20; // 错误:不能修改 const 成员变量std::cout << "Value: " << obj.value << std::endl;return 0;
}
5.2 修饰类成员函数
作用:表示该函数不会修改类的成员变量。
语法:在函数定义后加 const
。
#include <iostream>
class MyClass {
private:int data;
public:MyClass(int d) : data(d) {}int getData() const { // const 成员函数return data;}// void setData(int d) const { data = d; } // 错误:const 函数不能修改成员变量
};int main() {MyClass obj(10);std::cout << "Data: " << obj.getData() << std::endl;return 0;
}
6. const
与 #define
的比较
示例对比:
#define PI 3.14
const double pi = 3.14;int main() {// PI = 3.15; // 错误:#define 定义的值是文本替换,不是变量// pi = 3.15; // 错误:const 定义的值不能修改return 0;
}
7. 小结
const
的作用:
-
保护变量:限制变量或指针的可修改性,增强安全性。
-
优化函数:保护函数参数,避免意外修改。
-
增强表达力:通过
const
声明,提高代码的可读性和维护性。 -
C++ 专用特性:在类中可修饰成员变量和成员函数,支持更复杂的只读逻辑。
const
是代码中保证不变性的强有力工具,在安全性、优化和可维护性方面至关重要。
三、 volatile
volatile
关键字用来修饰那些可能被意想不到地改变的变量,例如硬件寄存器中的值或并发线程中共享的变量。它告诉编译器不要对涉及这些变量的操作进行优化,确保每次读取都是从内存中读取最新的值。
1、volatile
的作用
防止编译器优化:
编译器在优化代码时,可能会将变量的值缓存在寄存器中,导致程序无法感知变量的实时变化。volatile
保证变量的值总是从内存中读取,而不是从寄存器缓存读取。
编译器在优化代码时,可能会做以下处理:
将变量的值缓存到寄存器中,避免重复访问内存。
在循环中,认为变量值不变,将其优化为常量。
volatile
禁止编译器对变量进行这些优化。
确保正确性:
对于可能被其他线程、中断服务程序(ISR)、硬件设备等修改的变量,volatile
确保程序访问的是最新值。
2、volatile
的典型应用场景
2.1 多线程编程
当一个变量可能被多个线程修改时,需要用 volatile
声明,以防止编译器优化。
volatile int flag = 0;void thread1() {while (flag == 0) {// 等待其他线程修改 flag}// 继续执行
}
void thread2() {flag = 1; // 修改 flag
}
如果没有 volatile
,编译器可能会将 flag == 0
优化为一个死循环,因为它认为 flag
的值不会改变。
2.2 硬件寄存器访问
与硬件交互时,寄存器的值可能在程序之外发生变化,必须使用 volatile
确保程序访问到最新值。
#define STATUS_REGISTER *((volatile int *)0x40000000)void checkStatus() {while ((STATUS_REGISTER & 0x01) == 0) {// 等待硬件设置状态寄存器的第 0 位}// 状态已改变
}
2.3 中断服务程序 (ISR)
中断服务程序可能会修改主程序中的变量,因此这些变量需要声明为 volatile
。
volatile int timer_flag = 0;void ISR() {timer_flag = 1; // 中断发生时修改变量
}int main() {while (timer_flag == 0) {// 等待中断}// 中断已发生return 0;
}
3、volatile
的特性与限制
作用:告诉编译器变量可能会被外部事件(硬件或线程)修改,因此每次访问变量时必须从内存中读取。
内存可见性:volatile
保证了 单线程环境 中的变量内存可见性,即从内存中读取最新值,但 不提供线程安全性(需要配合锁或原子操作)。
无法保证线程安全:volatile
仅保证变量值从内存中读取,但无法保证多个线程对同一变量的原子操作。例如:
volatile int counter = 0;void increment() {counter++; // 非线程安全,可能发生数据竞争
}
此时需要使用 互斥锁 。
无法控制操作顺序:
例如在多核处理器中,内存屏障(memory barrier)需要单独使用,volatile
无法确保操作的顺序。
4、volatile
的用法
4.1修饰普通变量
volatile int counter = 0;void modifyCounter() {counter++; // 确保每次操作都从内存读取
}
4.2 修饰指针
指针本身是 volatile:
int * volatile p;
含义:指针地址可能发生变化,但指针指向的值可以改变。
指针指向的值是 volatile:
volatile int *p;
含义:指针指向的值是可变的,必须从内存读取。
指针本身和指向的值都是 volatile:
volatile int * volatile p;
含义:指针本身和指针指向的值都可能被外部修改。
4.3缓存优化问题
假设没有使用 volatile
:
int flag = 0;void waitForFlag() {while (flag == 0) {// 循环等待}
}
在某些编译器中,while (flag == 0)
可能被优化为:
if (flag == 0) {while (true) {} // 死循环
}
因为编译器假定 flag
不会被外部修改。
添加 volatile
后:
volatile int flag = 0;void waitForFlag() {while (flag == 0) {// 每次读取最新的 flag 值}
}
4.4硬件寄存器问题
#define STATUS_REG *((volatile int *)0x40000000)void pollStatus() {while ((STATUS_REG & 0x01) == 0) {// 等待硬件设置状态寄存器的第 0 位}
}
如果没有 volatile
,编译器可能优化为:
int reg = STATUS_REG;
while ((reg & 0x01) == 0) {// 死循环,无法感知硬件变化
}
5、小结
注意事项:
-
对于需要确保线程安全的操作,需要配合 互斥锁 或 原子操作。
-
硬件编程中,寄存器值必须声明为
volatile
,否则可能导致严重的逻辑错误。
volatile
是嵌入式系统和并发编程中不可或缺的关键字,在适当的场景下使用它能够显著提高代码的正确性和健壮性。
相关文章:
嵌入式的C/C++:深入理解 static、const 与 volatile 的用法与特点
目录 一、static 1、static 修饰局部变量 2、 static 修饰全局变量 3、static 修饰函数 4、static 修饰类成员 5、小结 二、const 1、const 修饰普通变量 2、const 修饰指针 3、const 修饰函数参数 4. const 修饰函数返回值 5. const 修饰类成员 6. const 与 #defi…...
【数据库设计】软件系统需要同时设计注册日志表和登录日志表吗
是的,通常情况下,注册日志表和登录日志表是分别设计的,分别记录不同类型的事件信息。 注册日志表 记录用户的注册信息、注册方式以及是否成功等内容。登录日志表 记录用户每次登录的时间、IP 地址、设备信息、登录状态等内容。 尽管这两者看…...
vim 一次注释多行 的几种方法
在 Vim 中一次注释多行是一个常见操作。可以使用以下方法根据你的具体需求选择合适的方式: 方法 1:手动插入注释符 进入正常模式: 按 Esc 确保进入正常模式。 选择需要注释的多行: 移动到第一行,按下 Ctrlv 进入可视块…...
手机无法连接服务器1302什么意思?
你有没有遇到过手机无法连接服务器,屏幕上显示“1302”这样的错误代码?尤其是在急需使用手机进行工作或联系朋友时,突然出现的连接问题无疑会带来不少麻烦。那么,什么是1302错误,它又意味着什么呢? 1302错…...
Git(一)基本使用
目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件,并使用 git init 在该目录下创建一个本地仓库, 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…...
sklearn中常用数据集简介
scikit-learn库中提供了包括分类、回归、聚类、降维等多种机器学习任务所需的常用数据集,方便进行实验和研究,它们主要被封装在sklearn.datasets中,本文对其中一些常用的数据集进行简单的介绍。 1.Iris(鸢尾花)数据集…...
LRU缓存
什么是LRU缓存? LRU(Least Recently Used)是最近最少使用算法,是操作系统中用于分页置换的算法,如果要向内存中添加分页,并且内存分页已满的情况下,就选出最近一段时间最不常用的分页进行置换(…...
.net6 使用 FreeSpire.XLS 实现 excel 转 pdf - docker 部署
FreeSpire.XLS && Aspose.Cells包都可以实现。实现过程中发现如下问题: 本地测试通过, docker部署服务器后报错: The type initializer for Spire.Xls.Core.Spreadsheet.XlsPageSetupBase threw an exception. 由于缺少依赖…...
HttpServletRequest req和前端的关系,req.getParameter详细解释,req.getParameter和前端的关系
HttpServletRequest 对象在后端和前端之间起到了桥梁的作用,它包含了来自客户端的所有请求信息。通过 HttpServletRequest 对象,后端可以获取前端发送的请求参数、请求头、请求方法等信息,并根据这些信息进行相应的处理。以下是对 HttpServle…...
[Python3] Sanic 框架构建高并发的 Web 服务
在 Python3 中使用 Sanic 框架来构建高并发的 Web 服务时,Sanic 因其异步和基于事件驱动的架构能够很好地处理高并发请求。下面是如何使用 Sanic 的一些要点和示例代码。 1. 安装 Sanic 首先确保你安装了 Sanic,可以通过以下命令安装: pip…...
5.5 W5500 TCP服务端与客户端
文章目录 1、TCP介绍2、W5500简介2.1 关键函数socketlistensendgetSn_RX_RSRrecv自动心跳包检测getSn_SR 1、TCP介绍 TCP 服务端: 创建套接字[socket]:服务器首先创建一个套接字,这是网络通信的端点。绑定套接字[bind]:服务器将…...
【Flutter】搭建Flutter开发环境,安卓开发
Flutter是谷歌开源的一个跨平台开发的框架,方便好用,这里以Windows 上构建 Flutter Android 应用为例,记录下我搭建环境时碰到的一些问题以及解决。 第一步:参考官网:开发 Android 应用 | Flutter 中文文档 - Flutter …...
【机器学习】——朴素贝叶斯模型
💻博主现有专栏: C51单片机(STC89C516),c语言,c,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux…...
k8s rainbond centos7/win10 -20241124
参考 https://www.rainbond.com/ 国内一站式云原生平台 对centos7环境支持不太行 [lighthouseVM-16-5-centos ~]$ curl -o install.sh https://get.rainbond.com && bash ./install.sh 2024-11-24 09:56:57 ERROR: Ops! Docker daemon is not running. Start docke…...
ctfshow单身杯2024wp
文章目录 ctfshow单身杯2024wp签到好玩的PHPezzz_sstiez_inject ctfshow单身杯2024wp 签到好玩的PHP 考点:序列化反序列化 <?phperror_reporting(0);highlight_file(__FILE__);class ctfshow {private $d ;private $s ;private $b ;private $ctf ;public …...
深入解密 K 均值聚类:从理论基础到 Python 实践
1. 引言 在机器学习领域,聚类是一种无监督学习的技术,用于将数据集分组成若干个类别,使得同组数据之间具有更高的相似性。这种技术在各个领域都有广泛的应用,比如客户细分、图像压缩和市场分析等。聚类的目标是使得同类样本之间的…...
【代码pycharm】动手学深度学习v2-08 线性回归 + 基础优化算法
课程链接 线性回归的从零开始实现 import random import torch from d2l import torch as d2l# 人造数据集 def synthetic_data(w,b,num_examples):Xtorch.normal(0,1,(num_examples,len(w)))ytorch.matmul(X,w)bytorch.normal(0,0.01,y.shape) # 加入噪声return X,y.reshape…...
Python绘制太极八卦
文章目录 系列目录写在前面技术需求1. 图形绘制库的支持2. 图形绘制功能3. 参数化设计4. 绘制控制5. 数据处理6. 用户界面 完整代码代码分析1. rset() 函数2. offset() 函数3. taiji() 函数4. bagua() 函数5. 绘制过程6. 技术亮点 写在后面 系列目录 序号直达链接爱心系列1Pyth…...
sklearn学习
介绍:scaler:换算的意思 1. 归一化MinMaxScaler() 归一化的意思是将一堆数,如果比较离散,为了让数据更适合模型训练,将离散的数据压缩到0到1之间,以方便模型更高效优质的学习,而对数据的预处理…...
# [Unity] 【游戏开发】Unity开发基础2-Unity脚本编程基础详解
Unity脚本编程是创建互动式游戏体验的核心技能之一。本文将详细讲解Unity脚本编程的基础知识,包括变量和数据类型、程序逻辑、方法等方面,并通过实例展示如何使用这些基本知识完成简单功能的实现。 1. 新建Unity脚本的基本结构 当在Unity中创建一个脚本时,Unity会生成如下基…...
【强化学习的数学原理】第02课-贝尔曼公式-笔记
学习资料:bilibili 西湖大学赵世钰老师的【强化学习的数学原理】课程。链接:强化学习的数学原理 西湖大学 赵世钰 文章目录 一、为什么return重要?如何计算return?二、state value的定义三、Bellman公式的详细推导四、公式向量形式…...
C语言-数学基础问题
一.奇数、偶数问题 1.从键盘上输入一个整数,判断并输出它是奇数还是偶数。 //从键盘上输入一个整数,判断并输出它是奇数还是偶数。 main() {int i;printf("输入一个整数:\n");scanf("%d",&i);if(i%20)printf("它是偶数\n…...
2024算法基础公选课练习四(综合2)
一、前言 最后几个题确实有难度,这次有两题没整出来 二、题目总览 三、具体题目 3.1 问题 A: 水题系列1-B(班级排位) 思路 最暴力的思路是写线段树,然后暴力枚举两个端点,总体时间复杂度为O(n^2*logn)最坏会到1e9的数量级,可能…...
小程序-使用 iconfont 图标库报错:Failed to load font
官方默认可以忽略此错误,在清除缓存后首次刷新会显示此错误,重新渲染错误消失 解决方法: 在 iconfont 图标库选择项目设置 选中 Base64 保存,重新点击链接 -> 复制代码到项目中 操作步骤:...
鲸鱼机器人和乐高机器人的比较
鲸鱼机器人和乐高机器人各有其独特的优势和特点,家长在选择时可以根据孩子的年龄、兴趣、经济能力等因素进行综合考虑,选择最适合孩子的教育机器人产品。 优势 鲸鱼机器人 1)价格亲民:鲸鱼机器人的产品价格相对乐高更为亲民&…...
解决单元测试时找不到类名
场景: springboot单元测试mockito对mapper进行mock时: tk.mybatis.mapper.mapperexception: 无法获取实体类 XX.xx 对应的表名 分析: 使用了一个方法:Example examplenew Example(User.class); 进入源码后发现Entityhelper没…...
簡單易懂:如何在Windows系統中修改IP地址?
無論是為了連接到一個新的網路,還是為了解決網路連接問題,修改IP地址都是一個常見的操作。本文將詳細介紹如何在Windows系統中修改IP地址,包括靜態IP地址的設置和動態IP地址的獲取。 IP地址是什麼? IP地址是互聯網協議地址的簡稱…...
(详细文档!)java swing学生信息管理系统 +mysql
第一章:系统功能分析 1.1、系统简介与开发背景 学生信息管理系统是在信息化时代,特别是在教育领域中产生的。随着学校规模的不断扩大和信息化技术的不断发展,传统的纸质档案管理方式已经无法满足学校对学生信息管理的需求,因此需…...
OSG开发笔记(三十三):同时观察物体不同角度的多视图从相机技术
若该文为原创文章,未经允许不得转载 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143932273 各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究 长沙红胖子Qt…...
[极客大挑战 2019]BabySQL--详细解析
信息搜集 进入界面: 输入用户名为admin,密码随便输一个: 发现是GET传参,有username和password两个传参点。 我们测试一下password点位能不能注入: 单引号闭合报错,根据报错信息,我们可以判断…...
Java的字符串操作(二)(代码示例)
1. 字符串的定义 // 直接赋值方式定义字符串 String str1 "Hello World";// 使用new关键字定义字符串 String str2 new String("Hello World");// 可以通过打印对象的哈希码来查看是否是同一个对象(在一定程度上反映引用情况) Sy…...
2024-2025 ICPC, NERC, Southern and Volga Russian Regional Contest(ABCGJLN)
文章目录 N. Fixing the Expression思路code J. Waiting for...思路code C. DIY思路code L. Bridge Renovation思路code A. Bonus Project思路code G. Guess One Character思路code B. Make It Equal思路code N. Fixing the Expression 思路 签到题,只改变中间的字…...
SpringBoot(9)-Dubbo+Zookeeper
目录 一、了解分布式系统 二、RPC 三、Dubbo 四、SpringBootDubboZookeeper 4.1 框架搭建 4.2 实现RPC 一、了解分布式系统 分布式系统:由一组通过网络进行通信,为了完成共同的任务而协调工作的计算机节点组成的系统 二、RPC RPC:远程…...
现代密码学
概论 计算机安全的最核心三个关键目标(指标)/为:保密性 Confidentiality、完整性 Integrity、可用性 Availability ,三者称为 CIA三元组 数据保密性:确保隐私或是秘密信息不向非授权者泄漏,也不被非授权者使…...
websocket是什么?
一、定义 Websocket是一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端推送数据,而不需要客户端不断的轮询服务器来获取数据 与http协议不同,http是一种无状态的,请求,响应模式的协议(单向通信)&a…...
idea怎么打开两个窗口,运行两个项目
今天在开发项目的时候,前端希望运行一下以前的项目,于是就需要开两个 idea 窗口,运行两个项目 这里记录一下如何设置:首先依次点击: File -> Settings -> Appearance & Behavior ->System Settings 看到如…...
aws服务--机密数据存储KMS(1)介绍和使用
在AWS(Amazon Web Services)中存储机密数据时,安全性和合规性是最重要的考虑因素。AWS 提供了多个服务和工具,帮助用户确保数据的安全性、机密性以及合规性。AWS Secrets Manager、KMS(Key Management Service)是推荐的存储机密数据的AWS服务和最佳实践。这里先看KMS。 …...
怎么编译OpenWrt镜像?-基于Widora开发板
1.准备相应的环境,我使用的环境是VMware16ubuntu20.04,如图1所示安装编译所需的依赖包; sudo apt-get install build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch python3 python2.7 unzip zlib1g-…...
Android opencv使用Core.hconcat 进行图像拼接
Android 集成OpenCV-CSDN博客 import org.opencv.android.Utils; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import android.graphics.Bitmap; import android.graphics.BitmapFactor…...
小杨的N字矩阵c++
题目描述 小杨想要构造一个m*m 的 N 字矩阵( m为奇数),这个矩阵的从左上角到右下角的对角线、第1 列和第m 列都 是半角加号 ,其余都是半角减号 - 。例如,一个 5*5 的 N 字矩阵如下: --- -- -- -- --- 请…...
C 语言面向对象
面向对象的基本特性:封装,继承,多态 1.0 面向过程概念 当我们在编写程序时,通常采用以下步骤: 1. 将问题的解法分解成若干步骤 2. 使用函数分别实现这些步骤 3. 依次调用这些函数 这种编程风格的被称作 面向过程…...
初试无监督学习 - K均值聚类算法
文章目录 1. K均值聚类算法概述2. k均值聚类算法演示2.1 准备工作2.2 生成聚类用的样本数据集2.3 初始化KMeans模型对象,并指定类别数量2.4 用样本数据训练模型2.5 用训练好的模型生成预测结果2.6 输出预测结果2.7 可视化预测结果 3. 实战小结 1. K均值聚类算法概述…...
部署实战(二)--修改jar中的文件并重新打包成jar文件
一.jar文件 JAR 文件就是 Java Archive ( Java 档案文件),它是 Java 的一种文档格式JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,多出了一个META-INF/MANIFEST.MF 文件META-INF/MANIFEST.MF 文件在生成 JAR 文件的时候…...
C++中的原子操作:原子性、内存顺序、性能优化与原子变量赋值
一、原子操作与原子性 原子操作(atomic operation)是并发编程中的一个核心概念,指的是在多线程环境中,一个操作一旦开始,就不会被其他线程的操作打断,直至该操作完成。这种不可分割的特性保证了操作的原子…...
【JavaEE初阶】多线程初阶下部
文章目录 前言一、volatile关键字volatile 能保证内存可见性 二、wait 和 notify2.1 wait()方法2.2 notify()方法2.3 notifyAll()方法2.4 wait 和 sleep 的对比(面试题) 三、多线程案例单例模式 四、总结-保证线程安全的思路五、对比线程和进程总结 前言…...
数据结构(Java版)第二期:包装类和泛型
目录 一、包装类 1.1. 基本类型和对应的包装类 1.2. 装箱和拆箱 1.3. 自动装箱和自动拆箱 二、泛型的概念 三、引出泛型 3.1. 语法规则 3.2. 泛型的优点 四、类型擦除 4.1. 擦除的机制 五、泛型的上界 5.1. 泛型的上界的定义 5.2. 语法规则 六、泛型方法 6.1…...
[原创](Modern C++)现在C++的关键性概念: 通俗易懂的解释“多态“与“虚函数“的内在关系
常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共23年] 职业生涯: 21年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi、XCode、Eclipse、C Bui…...
python操作Elasticsearch
使用elasticsearch 6.x版本,操作es数据。 #! -*- coding:utf-8 -* import timefrom elasticsearch import Elasticsearch, helpersclass EstUtil:_instance Nonedef __new__(cls, *args, **kwargs):if not cls._instance:cls._instance super(EstUtil, cls).__ne…...
【数据分享】2024年我国省市县三级的住宿服务设施数量(8类住宿设施/Excel/Shp格式)
宾馆酒店、旅馆招待所等住宿服务设施的配置情况是一个城市公共基础设施完善程度的重要体现,一个城市住宿服务设施种类越丰富,数量越多,通常能表示这个城市的公共服务水平越高! 本次我们为大家带来的是我国各省份、各地级市、各区…...
从尾到头打印链表 剑指offer
题目描述 输入一个链表的头节点,从尾到头反过来打印出每个节点的值。 链表节点定义如下: struct ListNode {int m_nKey;ListNode*m_pNext; }; 代码实现 栈实现: 递归实现: 但是用递归实现可能存在的问题:...