static关键字

在C语言中

  • 1.static全局变量:

static全局变量:其中.text段保存进程所执行的程序二进制文件,.data段保存进程所有的已初始化的全局变量,.bss段保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data段和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。
当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。

#include "file1.h"
static char* h = "hello!";
void printStr()
{
        printf("%s\n", hello);
}

//file2.c是主程序所在文件,file2.c中如果引用hello会编译出错

#include "file1.h"
int main()
{
        printStr();
        printf("%s\n", h);       //此处无法用引用file1.c中的h
        return 0;
}
  • 2.static局部变量:

普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。局部变量也可以在堆上动态分配,但是记得使用完这个堆空间后要释放之。
static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有如下几个区别:
1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。
2)访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。
3)值:静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。

注意:由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。需要多加注意。

void printStr()
{
        int normal = 0;
        static int stat = 0;        //this is a static local var
        printf("normal = %d ---- stat = %d\n",normal, stat);
        normal++;
        stat++;
}
//为了便于比较,两个变量:普通局部变量normal和静态局部变量stat,它们都被赋予初值0;

int main()
{
printStr();
printStr();
printStr();
printStr();
printf("call stat in main: %d\n",stat);//此处不能用stat因为是另外一个函数的static局部变量,报错未定义标识符stat
return 0;
}
//输出0 0  | 0 1 | 0 2 | 0 3
  • 3.static函数:
    当程序中有很多个源文件的时候,肯定会让某个源文件只提供一些外界需要的接口,其他的函数可能是为了实现这些接口而编写,这些其他的函数你可能并不希望被外界(非本源文件)所看到,这时候就可以用static修饰这些“其他的函数”。
    所以static函数的作用域是本源文件,可以把它想象为面向对象中的一个源文件中private函数就可以了。
//头文件中:
#include <stdio.h>
static int called();
void printStr();

#include "file1.h"
static int called()
{
        return 6;
}
void printStr()
{
        int returnVal;
        returnVal = called();      //此处是可以调用called函数
        printf("returnVal=%d\n",returnVal);
}

#include "file1.h"
int main()
{
        int val;
        val = called();     //此处识别不了called
        printStr();
        return 0;
}

以上内容借鉴https://www.cnblogs.com/JMatrix/p/8194009.html,在此感谢作者!

在C++中

总结一下static在类中修饰成员变量,和成员函数的作用:

  • 1.修饰成员变量:
    static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量

有以下特性:
1>.静态成员为所有类对象所共享,不属于某个具体的实例.意思是这个变量对于每个对象来说都是一个变量。是共同可以拥有的。
2>.静态成员变量必须在类外定义/初始化,定义时不添加static关键字。如果在类内定义,那么每创建一个对象,就将count的值给重新赋值修改了。那么他共享的意义就没有了
3>.类静态成员可用类名::静态成员(共享的是类的属性,不随对象)||对象.静态成员来访问
4>.静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值
5>.静态变量不在对象中,因而对象的大小不包含成员变量
应用:求Date总共创建了多少个有效对象?

class A1{
public:
	A1()
	{
		count++;

	}
	A1(const A1 &x)
	{
		count++;
	}
	~A1(){
		count--;
	}
private:
	int x;
public:
	static int count;
};
int A1::count = 0;    //静态成员变量是类的属性

void  Test()
{
	A1 x1;
	A1 x2;
	A1 x3(x1);
}
int main()
{
	Test();
	A1 x4;
	A1 x5;
	// 静态成员变量是所有类对象共享的成员变量,不属于某个具体的对象,以下输出结果一样
	cout << x4.count << endl;
	cout << x5.count << endl;
	return 0;
}
class A1{
public:
	A1()
	{
		

	}
	A1(const A1 &x)
	{
		
	}
	~A1(){
		
	}
	static int Getcount()
	{
		return count;
	}
private:
	int x;
	static int count;
};



int main()
{
	A1 x1;
	cout << sizeof(x1) << endl;    //-->4
	system("pause");
	return 0;
}
  • 2.修饰成员函数:
    用static修饰的成员函数,称之为静态成员函数。当要在其他函数里读取私有的静态成员,可用一个静态函数来读取
    特性:
    1>静态成员函数没有隐藏的this指针,不能访问任何非静态成员
    2> 成员函数也不属于任何一个对象,访问也可以使用上面所述的两种方法来访问.
class A1{
public:
	A1()
	{
		count++;

	}
	A1(const A1 &x)
	{
		count++;
	}
	~A1(){
		count--;
	}
	static int Getcount()
	{
		return count;
	}
private:
	int x;
	static int count;
};
int A1::count = 0;    

void  Test()
{
	A1 x1;
	A1 x2;
	A1 x3(x1);


}


int main()
{
	Test();
	A1 x4;
	A1 x5;
	
	//cout << x4.count << endl;  
	//cout << A1::count << endl;//这个两个方法是无法访问的

	cout << x5.Getcount() << endl;
	cout << A1::Getcount() << endl;//这两个方法是可以访问的
	return 0;
}

在这里插入图片描述

通过对比,可有以下可得结论

  1. 静态成员函数不可以调用非静态成员函数 原因很简单,上面说静态成员函数中不会传this指针,而非静态成员函数是需要this指针传入的,因而在静态成员函数中调用非静态成员函数是无法给非静态成员函数传入this指针的
    2.非静态成员函数可以调用类的静态成员函数 静态函数不需要this指针,非静态成员函数不影响静态的
    https://www.runoob.com/w3cnote/cpp-static-usage.html
### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值