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

目录
  • C语言
    • 隐藏
      • 场景演示
      • 解决方法
    • 保持变量内容的持久
    • 默认初始化为0
  • Cpp
    • static类成员变量
    • static类成员方法
    • 单例模式
  • 总结

C语言

隐藏

场景演示

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

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

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

运行结果

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

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

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

解决方法

声明和定义分离

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

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

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

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

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

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

使用static关键字及缺陷

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

a.h

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

代码结构

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

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

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

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

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

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);
}

保持变量内容的持久

  • 全局静态变量

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

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

总结

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

(0)

相关推荐

  • 详解c++中的 static 关键字及作用

    注:若没有特指是 静态成员时,默认都是普通成员: 1 类中的普通成员 类中的成员变量 和 成员函数 是分开存储的.其中, 1)每个对象都有独立的成员变量:成员变量可以存储在 栈空间.堆空间.全局数据区: 2)所有对象共享类的成员函数:成员函数 只能存储在 代码段: 2 类中的静态成员(static) 类中的静态成员 1.用 static关键字 修饰: 2.可以用 类名::成员名 访问 静态成员: 3.静态成员 属于 整个类: 4.静态成员 是所属类的成员,其它类不能访问: 5.静态成员的内存分配

  • C++面试基础之static关键字详解

    前言 static是 c++ 的关键字,顾名思义是表示静态的含义.它在 c++ 中既可以修饰变量也可以修饰函数.那当我们使用 static 时,编译器究竟做了哪些事情呢? 早先面试中被问到 static 关键字,感觉既熟悉又陌生.熟悉是都知道如何去使用它,陌生又来自不知道它究竟对我们程序做了什么.今天就来好好复习下这个关键字,本文的重点也在第三部分. 先看一下示例代码: test1.cpp #include <iostream> extern int a_int; extern void fu

  • 一文读懂c++之static关键字

    一.静态变量 与C语言一样,可以使用static说明自动变量.根据定义的位置不同,分为静态全局变量和静态局部变量. 全局变量是指在所有花括号之外声明的变量,其作用域范围是全局可见的,即在整个项目文件内都有效.使用static修饰的全局变量是静态全局变量,其作用域有所限制,仅在定义该变量的源文件内有效,项目中的其他源文件中不能使用它. 块内定义的变量是局部变量,从定义之处开始到本块结束处为止是局部变量的作用域.使用static修饰的局部变量是静态局部变量,即定义在块中的静态变量.静态局部变量具有局

  • 深入浅析c/c++ 中的static关键字

    static关键字 1,static 成员变量 static 成员变量不随着对象的创建而开辟内存空间.也就是说,不管从哪个对象去看static成员变量,都是一样的. 2, static 成员方法 static 成员方法里不可以调用非static 成员方法. 非static 成员方法里可以调用static 成员方法. 原因:非static 成员方法里是没有this指针的,所以在里面调用非static 成员方法时,无法传递this指针.static 成员方法不需要this指针. 重点:初始化stat

  • C++语言基础 this和static关键字

    一.this关键字 this是一个指针,可用其访问成员变量或成员函数 下面是使用this的一个完整示例: #include <iostream> using namespace std; class Student{ public: void setname(char *name); void setage(int age); void setscore(float score); void show(); private: char *name; int age; float score;

  • C/C++中static,const,inline三种关键字详细总结

    一.关于staticstatic 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性,下面我将从 static 修饰符的产生原因.作用谈起,全面分析static 修饰符的实质. static 的两大作用: 一.控制存储方式 static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间. 引出原因:函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保

  • iOS开发中关键字const/static/extern、UIKIT_EXTERN的区别和用法

    一.前言 对于刚入行的新手们这些关键字可能会经常搞混淆或不清楚它们的意思和用法吧,即使在网上看了区别,但是很久不用下次又不清楚了,而且即使清楚自己的代码恐怕也很少用起来吧.通过阅读别人优秀的代码总会发现一些常用的关键字,随着自己的编程经验的积累慢慢的明白的. 二.关键字const/static/extern/UIKIT_EXTERN的释义和用法 1.const 这个单词翻译成中文是"常量"的意思.在程序中我们知道"常量"的值是不能变的,固定的.所以const关键字的

  • Java类中this关键字与static关键字的用法解析

    目录 前言 1:修饰属性,表示调用类中的成员变量. 2:this修饰方法 3:this表示当前对象的引用 前言 今天给大家总结介绍一下Java类中this关键字和static关键字的用法. this关键字用法: this.属性可以调用类中的成员变量 this()可以调用类中的构造方法 1:修饰属性,表示调用类中的成员变量. 代码示例: public class Student { public String name; public int age; public String school;

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

    目录 C语言 隐藏 场景演示 解决方法 保持变量内容的持久 默认初始化为0 Cpp static类成员变量 static类成员方法 单例模式 总结 C语言 隐藏 场景演示 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性.会导致符号表认为存在同名全局变量和函数发生碰撞. 场景:全局的变量/函数在.h中会在多个.cc文件中拥有且全局可见有链接问题. a.h #pragma once #include<stdio.h> void Test() { printf(&

  • springboot static关键字真能提高Bean的优先级(厉害了)

    生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BAT的乌托邦]逐个击破,深入掌握,拒绝浅尝辄止. 前言 各位小伙伴大家好,我是A哥.关于Spring初始化Bean的顺序问题,是个老生常谈的话题了,结论可总结为一句话:全局无序,局部有序.Spring Bean整体上是无序的,而现实是大多数情况下我们真的无需关心,无序就无序呗,无所谓

  • Java关键字详解之final static this super的用法

    目录 1. final 关键字: 2. static 关键字: 3. this 关键字: 4. super 关键字: final,static,this,super 关键字总结 正文开始@Assassin 1. final 关键字: final 关键字,意思是最终的.不可改变的,初始化之后就不能再次修改 ,用来修饰类.方法和变量,具有以下特点: final 修饰的类不能被继承,final类中的所有成员方法都会被隐式的指定为 final 方法: final 修饰的方法不能被重写: final 修饰

  • Java中的static关键字修饰属性和方法(推荐)

    目录 static关键字 1.static修饰属性(静态属性) 1.1.哪些成员属性可以被static修饰. 1.2.静态属性的访问. 2.static关键字修饰方法 1.那些方法可以使用static修饰 2.常见的问题 static关键字 static关键词与对象无关.static关键字主要修饰四个部分的内容 这里我们主要介绍static修饰属性和修饰方法. 1.static修饰属性(静态属性) 1.1.哪些成员属性可以被static修饰. 我们把static修饰的属性称为静态属性,又叫类属性

  • C++示例讲解friend static const关键字的用法

    目录 一.友元函数 1.1重载operator<< 1.2友元函数 1.3友元类 二.关键字const 2.1const修饰类的成员函数 三.关键字static 3.1static类成员 3.2面试题 总结 一.友元函数 1.1重载operator<< 问题:现在我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数.因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置.this指针默认是第一个参数也就是左操

  • 详解Java中static关键字和内部类的使用

    目录 一. static 关键字 1. static修饰成员变量 2. static修饰成员方法 3. static成员变量的初始化 二. 内部类 1. 实例内部类 2. 静态内部类 3. 局部内部类 4. 匿名内部类 一. static 关键字 在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的. 1. static修饰成员变量 static修饰的成员变量,称为静态成员变量 [静态成员变量特性]: 不属于某个具体的对象,是类的属

  • C++类中的static和const用法实例教程

    static和const是C++程序设计中非常重要的概念,本文实例列举了C++类中的static和const的规则和用法.供大家参考借鉴.具体说明如下: 首先以代码用来举例说明.示例代码如下: class A { public: A():m(10) //const成员必须在构造函数的初始化构造列表中初始化 { q = 40; } void fun1()const { m++; //错误.const成员是常量,不能改变其值. n++; //正确.static变量n属于类,但是每个对象的函数都可以访

  • PHP自定义函数获取搜索引擎来源关键字的方法

    本文实例讲述了PHP自定义函数获取搜索引擎来源关键字的方法.分享给大家供大家参考,具体如下: 获取搜索引擎来源关键字的函数: function getKeywords() { // 搜索引擎关键字映射 static $host_keyword_map = array( 'www.baidu.com' => 'wd', 'v.baidu.com' => 'word', 'image.baidu.com' => 'word', 'news.baidu.com' => 'word', '

随机推荐