热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

这篇文章主要介绍“CC++的关键字static怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“CC++的

这篇文章主要介绍“C/C++的关键字static怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C/C++的关键字static怎么使用”文章能帮助大家解决问题。

    C语言

    隐藏

    场景演示

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

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

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

    a.h

    #pragma once
    #include
    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

    运行结果

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

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

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

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

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

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

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

    解决方法

    声明和定义分离

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

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

    a.h

    #include
    void Test();

    a.c

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

    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

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

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

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

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

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

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

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

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

    使用static关键字及缺陷

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

    a.h

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

    代码结构

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

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

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

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

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

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

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

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

    a.h

    #pragma once
    #include
    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);
    }

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

    保持变量内容的持久

    • 全局静态变量

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

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

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

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

    • 局部静态变量

    内存位置:静态存储区

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

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

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

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

    默认初始化为0

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

    #include 
    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又只能在当前文件可见。因此真要处理成全局的就使用单例模式。

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

    关于“C/C++的关键字static怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程笔记行业资讯频道,小编每天都会为大家更新不同的知识点。


    推荐阅读
    • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
    • 本文介绍了基于c语言的mcs51单片机定时器计数器的应用教程,包括定时器的设置和计数方法,以及中断函数的使用。同时介绍了定时器应用的举例,包括定时器中断函数的编写和频率值的计算方法。主函数中设置了T0模式和T1计数的初值,并开启了T0和T1的中断,最后启动了CPU中断。 ... [详细]
    • c语言\n不换行,c语言printf不换行
      本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
    • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
    • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
    • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
    • OO第一单元自白:简单多项式导函数的设计与bug分析
      本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
    • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
    • C语言判断正整数能否被整除的程序
      本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
    • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
    • 在C#中,使用关键字abstract来定义抽象类和抽象方法。抽象类是一种不能被实例化的类,它只提供部分实现,但可以被其他类继承并创建实例。抽象类可以用于类、方法、属性、索引器和事件。在一个类声明中使用abstract表示该类倾向于作为其他类的基类成员被标识为抽象,或者被包含在一个抽象类中,必须由其派生类实现。本文介绍了C#中抽象类和抽象方法的基础知识,并提供了一个示例代码。 ... [详细]
    • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
    • Python如何调用类里面的方法
      本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
    • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
    • 如何搭建Java开发环境并开发WinCE项目
      本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
    author-avatar
    Coco__GLL
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有