我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C/C++的关键字之static你了解吗

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C/C++的关键字之static你了解吗

C语言

隐藏

场景演示

当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。会导致符号表认为存在同名全局变量和函数发生碰撞。

场景:全局的变量/函数在.h中会在多个.cc文件中拥有且全局可见有链接问题。

image-20220221183611526

a.h

#pragma once
#include<stdio.h>
void Test()
{
  printf("I am test..\n");
}

b.c

#include"a.h"
void call()
{
    Test();
}

c.c

#include"a.h"
int main()
{
   Test();   
}

makefile

all:c
c:c.o b.o
	gcc -o $@ $^ 
c.o:c.c
	gcc -c $^ 
b.o:b.c
	gcc -c $^ 
.PHONY:clean
clean:
	rm -rf *.o c

运行结果

image-20220221183828906

此时查看b.oc.o符号表。(readelf -s xxx.o)

image-20220221183926498

image-20220221183944564

可以看到双方的.o符号表中都认为有一个GLOBAL全局函数的Test,两者汇编阶段形成的符号表此时在汇总的阶段就会产生同名全局函数冲突。

此时在两者的二进制文件里都认为各自拥有Test()函数,且都在全局。而全局函数只能有一个名字(注:重载是底层重新命名了)。虽然我们知道两个Test()是同一个,但是link的时候认为有两个同名函数实现,因此报link错。

image-20220221184323225

解决方法

声明和定义分离

养成声明和定义分离的习惯,在.h中只声明不定义。在.c文件中定义。

image-20220221184956320

a.h

#include<stdio.h>
void Test();

a.c

#include"a.h"
void Test()
{
    cout<<"I am test..."<<endl;
}

makefile

all:c
c:c.o b.o a.o
	gcc -o $@ $^ 
c.o:c.c
	gcc -c $^ 
b.o:b.c
	gcc -c $^ 
a.o:a.c
	gcc -c $^ 
.PHONY:clean
clean:
	rm -rf *.o c

image-20220221185142988

为什么此时就可以正常运行了?

依然查看符号表,可以发现b.o和c.o中此时只是给Test声明留了一个全局的NOTYPE位置。

image-20220221185244568

而在a.o中定义Test(),因此a.o中是func类型。

image-20220221185352451

最后三个.o文件链接的时候确定Test()实际在最后生成的.out文件中的虚拟内存地址。运行时加载到内存中,之后的详细过程就是linux创建进程中的事情。

image-20220221185617070

使用static关键字及缺陷

那如果我就是想要直接在.h中存放一个公共的全局的对象来供其他所有文件使用呢?使用static关键字。

a.h

#pragma once
#include<stdio.h>
static void Test()
{
  printf("I am test..\n");
}

代码结构

image-20220221185854507

此时为什么又成立呢?两者.o文件中为什么对同名的全局函数包容了呢?可以看到此时两者的符号表中仍然是func,按照场景演示中的例子,应该报错的。

image-20220221185942306

此时反汇编查看Test()函数地址。我们发现此时生成了两个test函数,不过函数地址不同。

结论:static函数作用域仅在自己所在文件,其实是编译后不同文件下的同名static函数会有不同的内部命名

不同.c文件include了static变量之后该变量只在各自包含该变量的.c中可见。

image-20220221190131277

既然生成了两份,我们就可以发现,如果是一个静态的全局变量,我们分别进行修改实际上对两个不同的变量进行修改的。如果要解决全局变量统一性访问,保证全局变量不可变即可。另外一种方式就是使用单例模式。

a.h

#pragma once
#include<stdio.h>
static int a =0;

b.h

#include"a.h"
void call();

b.c

#include"b.h"
void call()
{
   a = 1;
   printf("a=%d\n",a);
}

c.c

#include"b.h"
int main()
{
   a=2;
   printf("a=%d\n",a); 
   call();
   printf("a=%d\n",a);
}

image-20220221195458359

保持变量内容的持久

  • 全局静态变量

在全局变量前加上关键字static,全局变量就定义成一个全局静态变量。

内存中位置:静态存储区,在整个程序运行期间移植存在。

初始化:未经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他是被显示初始化)。

作用域:全局静态变量是从定义指出开始,到文件结尾,在声明他的文件之外是不可见的。

  • 局部静态变量

内存位置:静态存储区

初始化:未经初始化的局部静态变量会被自动初始化为0(自动对象的值是任意的,除非他是被显示初始化)。

作用域:为局部作用域,当定义他的函数或者语句块结束时,作用域结束。但是当局部静态变量离开作用域后,并没有被销毁,依然驻留在内存中,只不过我们不能再对它进行访问,直到该函数再次被调用,并且值不变。

如下的count变量作用域在test函数中,而生命周期是整个程序。在第一次进入test()的时候会初始化,之后进入test()就不再执行第5行代码了。

#include<stdio.h>
void test()
{
    static int count =0;
    count++;
}
int main()
{
    for(int i =0 ; i < 10 ; i++ ) test();
}

默认初始化为0

默认初始化为0:在静态存储区,内存中所有的字节默认值都是0x00。

#include <stdio.h>
int a;
int main(void)
{
    int i;
    static char str[10];
    printf("integer: %d;  string: (begin)%s(end)", a, str);
    return 0;
}

Cpp

static类成员变量

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;静态的成员变量一定要在类外进行初始化

  • 静态变量属于整个类,所有对象,生命周期在整个程序间运行
  • 在类成员函数中,可以随便访问

static类成员方法

用static修饰的成员函数,称之为静态成员函数。(因为该成员变量没有this指针)

static成员函数,没有this指针,不使用对象就可以调用–>fun::。

静态成员函数可以调用非静态成员函数(/成员)吗?不行。没有this指针

非静态成员函数可以调用类的静态成员函数吗?可以

class Date
{
    public:
    	Date(int year=0,int month=1,int day=1)
        {
        }
    	void f1()
        {
        }
    	static void f2()
        {
		   f1();//没有this指针
        }
    private:
}
class Date{
public:
    	void f3()
        {
            f4();//突破类域+访问限定符就可以访问 Date::f4();/对象.f4()
            //类里面是一个整体都在类域中,类里面不受访问限定符限制
        }
    	static void f4()
        {
        }
private:
};

单例模式

  • 单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

1.如何保证全局(一个进程中)只有一个唯一的实例对象

参考只能在堆上创建对象和在栈上创建对象,禁止构造和拷贝构造及赋值。

提供一个GetInstance获取单例对象。

2.如何提供只有一个实例呢?

饿汉模式和懒汉模式。

3.使用场景

由于全局的变量在.h中会在多个.cc文件中拥有且可见容易有链接问题。而static又只能在当前文件可见。因此真要处理成全局的就使用单例模式。

具体的单例模式在特殊类设计中提及。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!   

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C/C++的关键字之static你了解吗

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C/C++的关键字static怎么使用

这篇文章主要介绍“C/C++的关键字static怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C/C++的关键字static怎么使用”文章能帮助大家解决问题。C语言隐藏场景演示当我们同时编译
2023-06-29

一文带你了解C语言中static关键字的3个作用

static这个关键字是“静态”的意思,在C语言里主要有3个作用。这篇文章主要通过一些简单示例为大家详细讲讲这3个左右,感兴趣的小伙伴可以了解一下
2023-05-15

c++中static关键字的作用

在 c++ 中,static 关键字用于声明变量或函数,使其仅在声明的范围内可见,在程序启动时分配内存,并且保持不变。此外,它还允许跨函数和文件共享数据、存储常量、创建静态局部变量并定义类级函数。C++ 中 static 关键字的作用在
c++中static关键字的作用
2024-05-15

关于C++中的static关键字的总结

C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用
2022-11-15

C#中static关键字的具体使用

C#中static关键字声明静态成员,与类相关,不依赖于对象实例。包括静态字段(共享数据)、静态方法(类级功能)和静态类(不能创建实例)。静态成员共享性强,类级访问,线程安全,持久存在。优点是共享数据、提供工具方法、提高效率;缺点是可测试性差、可扩展性受限、可重用性低。最佳实践是仅在必需时使用,优先使用实例成员,依赖注入管理依赖关系,慎用静态类。
C#中static关键字的具体使用
2024-04-02

C语言中的Static关键字怎么用

这篇文章主要介绍C语言中的Static关键字怎么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、static关键字的基本含义首先,static关键字的意思是静态的,用于修饰局部变量,全局变量和函数,修改其数据储存
2023-06-26

c语言关键字static的作用是什么

在C语言中,关键字static有以下几种作用:1. 静态变量:static关键字可以用于声明静态变量,静态变量存储在静态存储区,在程序运行期间一直存在,其作用域为局部作用域,但其生命周期为整个程序运行期间。静态变量的初始值默认为0,只会被初
2023-09-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录