C++几个关键字总结——const、static、extern、volatile

2023-10-30

1.const

const 基本原理 : 被修饰的对象的值不可以被修改

const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。 

(1)const修饰基本数据类型

表示常量,必须进行初始化,有以下两种初始化的方式:

编译时初始化:   编译器在编译时会把所有用到j的地方都替换成对应常数,如const int a=42;,即这种情况下,编译器是不为常量a分配内存的

运行时初始化:初始值不是常量表达式, 如const int i=get_size();

(2)const修饰引用

表示对常量的引用,不能通过此引用修改它所指向的对象,只是限制了这个操作,并未限制它指向的对象(可以是非const的)

可以将用一个非常量对象来初始化一个指向常量的引用(类型能自动转换即可);不可以用一个常量对象初始化一个指向非常量的引用

(3)const修饰指针

区分以下几种形式:

int a = 0;
int *const b=a;     //b是指向非常量int的常量指针,指针本身不可变,即该指针的指向(存储的地址)不可变,但可以通过它修改它所指向的对象

const int c = 0;
const int *d = c;  //c是指向const int的非常量指针,也就是该指针所指的对象不可变,即不能通过指针去修改它所指向的对象
                   //但可以修改它自己的存放的地址(指向)


const int* const e = c;   //e是指向const int的常量指针,指针的指向和指针所指的对象都不可变

对于指向常量的非常量指针,也只是限制了通过此指针去修改该它所指的对象这样的操作,并未限制它所指象的对象(可以是非const的)

(4)const修饰常对象  

常对象是指对象常量,定义格式如下: 
class A;    const A a; 
A const a;    

定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。

const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数;

(5)const修饰函数形参

传递过来的参数在函数内不可以改变

(6)const修饰函数返回值

待补充

(7)const修饰成员函数

放在函数声明的最后面即形参列表的括号后面,如下:

class ClassName { 
public:     
int Fun() const;   
};

表示该函数不可以修改该类的成员变量的值,并且不可以调用类中非成员函数,但非const成员函数可以调用const成员函数;

(8)在多个文件共同使用一个const常量

2.static

主要有2种用法:

<1>限定作用域,比如

修饰全局变量-全局静态变量

修饰函数-静态函数

修饰成员变量

修饰成员函数

<2>保持变量内容持久化;

修饰局部变量-局部静态变量

(1)修饰全局变量

全局变量前加上关键字static,全局变量就定义成一个全局静态变量限定作用域)。

全局静态变量作用域被限定,只在定义它的文件之内可见,准确地说是从定义之处开始,到文件结尾。

test.c

#include <stdio.h>

static int s_a = 20; // 如果不想该变量被其它文件访问,则需要加上static

int get_a(void)
{
	return s_a;
}

main.c

#include <stdio.h>

extern int s_a;   
extern int get_a(void);
int main()
{
	//printf("s_a = %d\n", s_a);   无法打印s_a,因为它是static的
	printf("s_a = %d\n", get_a()); //我们可以使用函数接口来访问s_a
	return 0;
}

(2)修饰函数

在函数返回类型前加关键字static,函数就定义成静态函数静态函数只是在定义他的文件当中可见,不能被其他文件所用。

test.c

#include<stdio.h>


static void printf_static_func()
{
    printf("printf_static_func() be called\n");
}

void test()    //要在其他文件使用只能再加一层函数调用
{
    printf_static_func();
}

test2.c

#include<stdio.h>


static void printf_static_func()
{
    printf("printf_static_func() be called\n");
}

static void test()    //在其他文件中不可见,加了static,不会引起重定义错误
{
    printf_static_func();
}

main.c

#include <stdio.h>

extern void test();
int main()
{
	test();
	return 0;
}

使用原则:(1)某一个函数不想被其他模块所引用,则使用static进行修饰;

                  (2)不同的文件可能函数命名有相同,此时使用static进行修饰可以解决重名的问题。

(3)修饰局部变量

在局部变量之前加上关键字static,局部变量就成为一个局部静态变量

作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域结束。局部静态变量和普通局部变量的作用域是一模一样的,即都只能在定义它的函数或语句块中使用,在不同的作用域中的同名static变量的内存地址也不一样

生命周期:但是当局部静态变量离开作用域后,并没有销毁,而是仍然驻留在内存当中,该函数再次被调用,其值和前次调用退出时一样。

局部变量是定义在栈上,函数退出后变量就被销毁。

局部静态变量是定义在静态区,其在程序开始运行时就已经在内存里面。在整个程序结束时才会被销毁

#include <stdio.h>

void printf_call_count()
{
	int call_count = 0;     //与静态变量不在一块区域
	static int s_call_count = 0;//静态变量只初始化一次
	printf("origin s_call_count = %d\n", s_call_count);
	++s_call_count;
	printf("++s_call_count = %d\n", s_call_count);
	printf("1 s_call_count = %p,call_count = %p\n", &s_call_count, &call_count);

	{
		static int s_call_count = 0;    //与作用外的静态变量内存地址不一样
		++s_call_count;
		printf("2 s_call_count = %p\n\n", &s_call_count);
	}

}
int main()
{
	printf_call_count();  // 每次调用结果都不一样
	printf_call_count();
	printf_call_count();
	return 0;
}

(4)修饰成员变量-静态成员变量

一个类的成员为 static 时,即为静态成员,从属于于类,这个类无论有多少个对象被创建,这些对象共享这个 static 成员,

静态数据成员一旦被定义一直存在于程序的整个生命周期中 

静态成员变量初始化::

不是由类的构造函数初始化,一般不能在类的内部初始化静态成员变量,只是在类的内部声明,在类的外部定义和初始化,格式如下:

格式:数据类型 类名:: 静态数据成员名 = 

访问静态成员变量格式:

类名>::静态成员名

 如果创建了对象,也可以用对象来访问:

     对象名.静态成员名

     对象指针->静态成员名

#include <stdlib.h>
#include <iostream>

using namespace std;

class  demo {
public:
	demo() {}

	~demo() {
		cout << "~析构" << endl;
	}

public:
	int a;
	static  int b;
};
//初始化静态成员变量
int demo::b = 10;



int main(void) {
	demo demo1;
	demo demo2;

	//访问静态成员
	printf("demo::b = %d\n", demo::b);  //通过类访问
	printf("demo1.b = %d\n", demo1.b);  //通过对象访问
	printf("demo2.b = %d\n", demo2.b);

	demo::b = 100;   //通过类赋值

	printf("demo::b = %d\n", demo::b);
	printf("demo1.b = %d\n", demo1.b);
	printf("demo2.b = %d\n", demo2.b);

	return 0;
}

静态数据成员与普通数据成员的区别:

(1)静态数据成员的类型可以是它所属的类类型,而非静态数据成员,只能声明成它所属类的指针或引用

class Bar
{
public:
     ...........
private:
    static Bar mem1; //正确
    Bar *mem2;       //正确
    Bar mem3;        //错误
};

(2)可以使用静态成员变量作为默认实参,而普通成员变量不可以,因为它的值属于对象的一部分,这么做无法真正提供一个对象以便从中获取成员的值

(3)静态成员变量使用前必须进行初始化,而普通成员变量如果不初始化,会被默认初始化

(4)对于类中的static成员变量只有在静态区中的一块内存,在编译时确定,不随对象开辟新的空间;而普通成员会随对象开辟新的空间

(5)修饰成员函数

静态成员函数没有this指针,不能声明成const,不能在static函数体内使用this指针

成员函数不用通过作用域运算符就能直接使用静态成员

可以在类的内部定义静态函数,也可以在类的外部,但static关键字只能出现在类内部的声明语句中,只出现一次

在类外调用静态成员函数用 “类名 :: ”作限定词,或通过对象调用

静态成员函数不能调用非静态成员函数或变量,但非静态成员函数可以调用静态成员函数或变量,因为静态成员从属于类,非静态成员从属于对象,静态成员在编译时就确定,而这时对象还没有被创建,所以对非静态成员并没有确定的对象来访问,而在调用对象的非静态成员函数时,静态成员已经确定,所以能正确调用

静态成员函数的应用:

单例模式:

//定义一个指向当前类对象的static指针变量
//定义获取单例的接口函数
#include <stdlib.h>
#include <iostream>

using namespace std;

class  demo {
public:
	demo() {}

	~demo() {
		cout << "~析构" << endl;
	}

	/*单例模式*/
	static demo * getInstance() {
		if (single == NULL) {
			single = new demo();
		}

		return single;
	}

	//静态成员函数
	static void set_b(int _b) {
		b = _b;
	}

	static int get_b() {
		return b;
	}

public:
	int a;

private:
	static  int b;
	static  demo * single; //指向类的静态指针

	//static demo single;  虽然我们这样定义数据成员,但是在C++中没有空对象的概念,
	                    // 所以一般使用指针,来判断是否为空
};

int demo::b = 10;
demo * demo::single = NULL;

void test() {
	demo *d2 = demo::getInstance();
	cout << "d2->get_b()的值是:" << d2->get_b() << endl;
	cout << "d2->a 的值是:" << d2->a << endl;
	printf("d2 的指针是: %p\n", d2);
	d2->set_b(8888);
	d2->a = 8888;
}

int main(void) {

	//demo::b = 100;
	//没创建对象前,如何修改私有static 成员变量的值
	//使用static函数
	demo::set_b(100);

	demo demo1;
	demo1.set_b(1000);
	cout << "demo.get_b()的值是:" << demo::get_b() << endl;

	//测试单例模式
	demo * d1 = demo::getInstance();
	d1->set_b(6666);
	d1->a = 6666;
	cout << "d1->get_b()的值是:" << d1->get_b() << endl;
	cout << "d1->a 的值是:" << d1->a << endl;
	printf("d1 的指针是: %p\n", d1);

	test();
	cout << "after test(), d1->get_b()的值是:" << d1->get_b() << endl;
	cout << "after test(), d1->a 的值是:" << d1->a << endl;

	return 0;
}

这里对于single的定义不能声明非static成员变量,因为这样的话,就不能在getInstance()中使用single变量了,所以该类对象指针和创建实例的函数必须都为static,才方便外部使用类来调用来创建单一的实例

3.extern

extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义

(1)修饰变量

比如说:

ga.c中定义如下:

int g_a = 10;       // 定义一个全局变量

main.c中定义如下:

#include<stdio.h>

extern int g_a;   // 要在这个文件中使用别的文件中定义的变量就要加extern在本文件中定义,否则会报错
{
    printf("使用ga.c的变量:g_a = %d\n", g_a);
    return 0;
}

需要注意的点

(1)变量前有extern不一定就是声明,如果变量有被初始化则是定义,没有被初始化则为声明

extern int a =0 ;//定义一个全局变量g_a 并给初值。
int a =0;  //定义一个全局变量g_a,并给初值。

(2)而变量前无extern就只能是定义。

extern int g_a;    //声明一个全局变量g_a
int g_a; //定义一个全局变量g_a

(3)变量可以多次声明,但只能定义在一个地方。

注:定义要为变量分配内存空间声明不需要为变量分配内存空间

正确的用法:

《1》int a = 0;  //定义的时候赋予初始值,并在.c文件定义全局变量,不要在.h文件定义

《2》其他模块引用时

extern int a; // 声明即可。

(2)修饰函数

定义函数要有函数体,声明函数没有函数体并以分号结尾

函数同样可以多次声明,但只能在一个地方定义。

当前模块使用外部模块的函数,建议使用extern进行声明。

test.c

#include<stdio.h>
void test()
{
     printf("我是test.c的test()\n");
}

main.c

#include<stdio.h>

extern void test();
int main()
{
    test();
    return 0;
}

注意:因为声明函数没有函数体(还有以分号结尾),所以在声明函数的时候可以将extern省略掉。但一般是在头文件(.h文件)声明的时候才省略掉extern,如果是在其他c文件声明则建议加上extern,增强代码可读性。

(3)extern与头文件的联系

原则:

(1)不要在头文件(.h文件)定义全局变量;  全局变量定义在.c文件,在.h文件只是声明即可。因为全局变量可以多次声明,但只能定义一次,如果在头文件中定义全局变量,当头文件被多个文件包含时,就会因为重定义报错

  // test.h

extern int g_a;

  // test.c

int g_a = 10;

(2)在.h声明函数时可以不使用extern进行修饰,且也不要在头文件定义函数,函数定义放在.c文件。

4.volatile

(1)为什么用volatile?

C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:

volatile int i=10;
int a = i;
...
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;

volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。注意,在 VC 6 中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无 volatile 关键字,对程序最终代码的影响,输入下面的代码:

实例

#include <stdio.h> 
void main() 
{ 
    int i = 10; 
    int a = i; 
    printf("i = %d", a); 
    // 下面汇编语句的作用就是改变内存中 i 的值,但是又不让编译器知道

    __asm { 
        mov dword ptr [ebp-4], 20h 
    } 
    int b = i; 
    printf("i = %d", b); 
}

然后,在 Debug 版本模式运行程序,输出结果如下:

i = 10
i = 32

然后,在 Release 版本模式运行程序,输出结果如下:

i = 10
i = 32

输出的结果明显表明,Release 模式下,编译器对代码进行了优化,第二次没有输出正确的 i 值。下面,我们把 i 的声明加上 volatile 关键字,看看有什么变化:

实例

#include <stdio.h> 
void main() 
{ 
    volatile int i = 10; 
    int a = i; 
    printf("i = %d", a); 
    __asm { 
        mov dword ptr [ebp-4], 20h
    } 
    int b = i; 
    printf("i = %d", b); 
}

分别在 Debug 和 Release 版本运行程序,输出都是:

i = 10
i = 32

这说明这个 volatile 关键字发挥了它的作用。其实不只是内嵌汇编操纵栈"这种方式属于编译无法识别的变量改变,另外更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方:

  • 1) 中断服务程序中修改的供其它程序检测的变量需要加 volatile;
  • 2) 多任务环境下各任务间共享的标志应该加 volatile;
  • 3) 存储器映射的硬件寄存器通常也要加 volatile 说明,因为每次对它的读写都可能由不同意义;

(2)volatile 指针

和 const 修饰词类似,const 有常量指针和指针常量的说法,volatile 也有相应的概念:

修饰由指针指向的对象、数据是 const 或 volatile 的:

const char* cpch;
volatile char* vpch;

注意:对于 VC,这个特性实现在 VC 8 之后才是安全的。

指针自身的值——一个代表地址的整数变量,是 const 或 volatile 的:

char* const pchc;
char* volatile pchv;

注意:

  • (1) 可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。
  • (2) 除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。
  • (3) C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。

3、多线程下的volatile

有些变量是用 volatile 关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入 CPU 寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:

volatile  BOOL  bStop  =  FALSE;

(1) 在一个线程中:

while(  !bStop  )  {  ...  }  
bStop  =  FALSE;  
return;    

(2) 在另外一个线程中,要终止上面的线程循环:

bStop  =  TRUE;  
while(  bStop  );  //等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,
//因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,
//程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。

这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:

...  
int  nMyCounter  =  0;  
for(;  nMyCounter<100;nMyCounter++)  
{  
...  
}  
...

在此段代码中,nMyCounter 的拷贝可能存放到某个寄存器中(循环中,对 nMyCounter 的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter -= 1; 这个操作中,对 nMyCounter 的改变是对内存中的 nMyCounter 进行操作,于是出现了这样一个现象:nMyCounter 的改变不同步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++几个关键字总结——const、static、extern、volatile 的相关文章

  • Docker教程(二) - 将容器打包成Docker镜像、使用Dockerfile打包镜像

    本文章翻译自Docker的官方教程 有兴趣的同学可以上Docker官网进行play with docker学习 Docker的安装教程请参考这里 未定义 本文翻译自Docker官方教程Doing More With Docker Image
  • signature=d80926ab19028a2cf65e944ce710aef6,[Question] How to create interoperable timestamps?

    I m trying to create a little time stamping service using jsrsasign When creating timestamps these cannot be parsed veri
  • DMA大数据的接收发送与保存

    DMA大数据的接收发送与保存 一 DMA基本介绍 DMA 全称Direct Memory Access 即直接存储器访问 DMA传输将数据从一个地址空间复制到另一个地址空间 当CPU初始化这个传输动作 传输动作本身是由DMA控制器来实现和完
  • HAL库的TIM中断和输入捕获

    硬件 stm32f4xx 软件 keil5 HAL库 1 TIM中断 TIM3 首先先把TIM初始化 官方给的初始化函数是HAL TIM Base Init TIM HandleTypeDef htim 也就意味着我们要首先初始化好TIM
  • Vue2计算属性computed

    vue实例被创建 在触发beforeCreate之后 会做一些事情 其中就包括对computed的梳理 处理 vue会遍历computed配置的所有属性 为每一个属性创建一个watcher 并传入一个函数 传入的函数本质就是computed
  • 有关三次握手,四次挥手的超详细总结!!!

    有关三次握手 四次挥手的超详细总结 我们先来看一下三次握手和四次挥手的示意图 图示为三次握手 图示为四次挥手 一 三次握手和四次挥手的过程 三次握手 TCP建立连接的过程我们称之为3次握手 1 第一次握手 PC1使用一个随机的端口号向PC2
  • elasticsearch installation guide

    UBUNTU 14 04 LTS 安装 elasticseach同步MYSQL表并实现中文搜索 1 下载wget https download elasticsearch org elasticsearch elasticsearch el
  • 2023春计算机系统大作业

    2023春计算机系统大作业
  • Nginx对上游服务的心跳检测健康检查

    nginx对上游服务器的健康检查默认采用惰性策略 可以集成 nginx upstream check module模块来进行主动健康检查 nginx upstream check module支持tcp心跳和http心跳检测 TCP心跳检查
  • AndroidStuio插件开发-适用于jetbrains全家桶

    文章目录 创建项目 创建类 获取文件 解析文件 展示解析内容 写入文件 写了个类似Butter Knife的开发库 但是并没有与其配套的AndroidStudio插件 抽时间研究了以下IDEA的api文档 撸了一个对应的插件 源码在这里 之
  • 在idea中创建javaweb项目

    在idea中新建javaweb项目 一 在idea中新建javaweb项目 二 部署应用程序到tomcat的webapps目录 一 在idea中新建javaweb项目 1 打开idea 选择File gt new gt new projec
  • 提问的智慧

    How To Ask Questions The Smart Way 学习浏览 看到的优质文章留存 转载 仅供个人学习使用 侵删 原文链接 本指南英文版版权为 Eric S Raymond Rick Moen 所有 原文网址 http ww
  • javascript 异步编程

    这可能是个比较深的话题 何谓异步 笼统地说 异步在javascript就是延时执行 严格来说 javascript中的异步编程能力都是由BOM与DOM提供的 如setTimeout XMLHttpRequest 还有DOM的事件机制 还有H
  • JEESITE登录流程简单梳理

    http blog csdn net qinwang gz article details 53306037
  • 网络三种连接方式-地址转换模式

    VMware虚拟机NAT 地址转换模式 转载于 VMware虚拟机三种网络模式详解 NAT 地址转换模式 Linux教程 Linux公社 Linux系统门户网站 二 NAT 地址转换模式 刚刚我们说到 如果你的网络ip资源紧缺 但是你又希望
  • 小程序、微信H5、APP,移动端跨端相互跳转相关规则,2020/11最新总结

    这里只做总结与解释 细则可以去相应官方文档查看 前情提要 其他小程序的appid可以在它的资料里直接查看 所以不是问题 H5 gt 小程序 gt 随便跳 通过微信jssdk openTagList wx open launch weapp
  • ubuntu(20.04)+linux内核(5.17.3)编译内核

    该篇文档可以放心观看 里面的内容是我以便编译内核 一边记录写下的 所以如果按照文档来做 是绝对可以的哈 文章目录 前言 一 安装linux内核 二 开始前的准备工作 三 内核编译 1 将下载好的linux内核解压至 usr src 2 得到
  • 数据透视表右侧字段不见了,怎么办?

    数据透视表右侧字段不见了 怎么办 点击 右键 选择 显示字段列表

随机推荐

  • 网络套接字发送结构体及数据处理

    struct很基础 但是说实话 我还不是很了解 以下是借鉴别人的 转载地址 http blog chinaunix net uid 21372424 id 119782 html 一 最近在做嵌入式系统 与windows的网络通信 由于 这
  • Spring源码学习-MVC的WEB源码解析

    目录 SpringMVC官方文档 SpringMVC的父子容器 父子关系的定义 自定义快速启动器 启动过程 容器创建的过程 容器刷新启动 父子容器示例图 网络请求链路分析 DispatcherServlet请求链路 DispatcherSe
  • oracle 9i在线重定义,oracle 9i上在线重定义表【转】

    当前位置 我的异常网 数据库 oracle 9i上在线重定义表 转 oracle 9i上在线重定义表 转 www myexceptions net 网友分享于 2013 07 23 浏览 3次 oracle 9i下在线重定义表 转 转自 h
  • https安全解决方案证书certbot教程

    一 Let s Encrypt Certbot和Snap的关系 Let s Encrypt是一个免费 自动化和开放的证书颁发机构 由非营利的互联网安全研究小组 ISRG 为您提供 Certbot使用EFF的Certbot在您的网站上自动启用
  • 抖音一键生成的AI绘画火了,网友惊呼:有点东西

    在各大AI绘画软件争奇斗艳的时候 近期最火的AI绘画莫过于抖音一键生成的AI绘画特效 网友惊呼 有点东西 就连最近话题度超高的 汪小菲 也用AI绘画来 秀 恩爱了 AI绘画识别度还挺高 特别是关于大白志愿者的生成效果 AI竟然能识别生成天使
  • postman—post方式几种请求格式的区别

    文章目录 前言 一 multipart form data与x www form urlencoded区别 二 使用时的一些细节 三 传参注意点总结 关于发送请求传入参数 总结 前言 介绍了postman中 常用的几种数据传参的特点 一 m
  • Elasticsearch的数据备份和恢复以及迁移

    目录 1 为什么备份 2 数据备份 3 数据恢复 4 ES备份数据迁移目标服务器 5 脚本备份恢复 1 为什么备份 常见的数据库都会提供备份机制 以解决在数据库无法使用的情况下通过备份来恢复数据减少损失 Elasticsearch 虽然有良
  • Pytorch建模过程中的DataLoader与Dataset

    pre line height 125 td linenos normal color inherit background color rgba 0 0 0 0 padding left 5px padding right 5px spa
  • python每日学5:python工程(大型项目)的组织架构:包、模块、类、方法

    题外话 在大型项目中 往往一个个模块已经不够组织起项目了 就比如一个文件夹下放了上千个文件 那想找到某一个文件就会变得困难 管理学中有种说法 一个管理者最适合管理 的对象是7个 假如程序的基本单元是函数 一个类包含7个函数 一个模块包含7个
  • C#怎么判断一个Socket是否连接

    判断Socket是否连接上 需要通过发包来确认 1 检查一个Socket是否可连接 2 private bool IsSocketConnected Socket client 3 4 bool blockingState client B
  • openGL之API学习(八十一)glsl的双精度double-precision

    10年以前的旧显卡基本上是没有双精度的 新显卡使用双精度需要开启GL ARB vertex attrib 64bit 和 GL ARB gpu shader fp64扩展 并且显卡架构要在SM5以上 就算有些显卡支持双精度类型 但是一些函数
  • java学生信息管理系统MVC架构

    一 项目结构 学生信息管理系统分三层进行实现 student java主要提供数据 cotroller java的功能是绑定试图和计算数据 Stuview java用于单一的用来显示数据 二 源码 1 1 Student 类 FileNam
  • 利用altium怎么生成PDF及怎么1:1打印文档

    画完板子之后 还要生成原理图PDF文档 供其他设计人员参考和指正 上图红框标注的两个地方 分别用于打印预览设置和生成原理图PDF 那么若是生成原理图PDF文档 则选择smart PDF即可 点击smart PDF后 点击next 上图中可以
  • vs如何断点?如何判断循环语句哪次出问题?

    红色的小点 按Fn F9 鼠标打字停在哪一行就会在哪一行 可以切换断点 再按一下则小红点消失 黄色的箭头 按Fn F10 再按Fn F10 就会到下一行 如果按Fn F5箭头会直接跳到红色的小点处 怎么看循环语句哪一次循环出问题呢 在断点
  • 算法:用Java实现双轴快速排序(DualPivotQuickSort)

    本文是用Java实现双轴快速排序 我找不到参考的文章地址了 十分抱歉 在此感谢参考文章的原作者 是你给了我思路和灵感 双轴快速排序和普通的快速排序不同的地方在于 普通的快速排序选出一个数字 作为一个基准值 然后通过数组值交换的方式 让左边区
  • Ant Design Pro项目中 提示:找不到模块“@ant-design/pro-components”或其相应的类型声明

    Ant Design Pro中在使用 StatisticCard 指标卡组件时候 按照官方的文档从 ant design pro components 中引入这个组件发现会报错 提示找不到模块 ant design pro componen
  • [659]linux安装RabbitMQ

    文章目录 安装Erlang 安装rabbitmq 关闭防火墙 否则非本地设备无法访问RabbitMQ服务 查看RabbitMQ运行状态 设置开机启动 添加用户 删除一个用户 修改用户的密码 设置用户角色 查看用户 设置用户权限 添加虚拟机
  • java 打印 发票_基于Excel和Java自动化:发票生成器

    对于销售人员 使用Excel创建发票是很常见的 但是该过程通常涉及许多容易出错的手动操作 例如输入数据 复制 粘贴等 如何实现一个可以将数据从数据库自动填充到发票Excel模板中 而无需再辛苦手动输入 从繁重的手动录入中解脱出来 并且避免认
  • win10计算器rsh_厉害了我的哥!win10计算器自带程序员模式太强大了!

    生活工作中常常会遇到用计算器的地方 比如算工资 算房贷啦 算卡路里等 一个有诸多功能的计算器能帮你省去大部分时间 你们知道吗 在windows计算器里 竟然还有程序员模式 可进行各种逻辑运算 快来和小编一起来看一下吧 相信大家Windows
  • C++几个关键字总结——const、static、extern、volatile

    1 const const 基本原理 被修饰的对象的值不可以被修改 const 推出的初始目的 正是为了取代预编译指令 消除它的缺点 同时继承它的优点 1 const修饰基本数据类型 表示常量 必须进行初始化 有以下两种初始化的方式 编译时