C/C++ | 每日一练 (3)

news/2025/2/25 8:01:34

💢欢迎来到张胤尘的技术站
💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥

文章目录

  • C/C++ | 每日一练 (3)
    • 题目
    • 参考答案
      • 静态变量
        • 静态局部变量
        • 静态全局变量
        • 静态变量可见性的底层实现
        • 静态变量的初始化
          • 静态局部变量
          • 静态全局变量
          • 内存模型
      • 对象静态成员

C/C++ | 每日一练 (3)

题目

c 静态变量和 c++ 静态变量的区别?

参考答案

cc++static 关键字都是用于定义静态变量的,但是在个别使用细节上还是存在一定的区别。

静态变量

不管是在 c 或者 c++ 中静态变量可以用于局部静态变量和全局静态变量。

静态局部变量

定义在函数内部,生命周期为程序的整个运行时间,但作用域仅限于定义它的函数。

#include <stdio.h>

int func()
{
    static int localVar = 1; // 局部静态变量,只在func内可见
    ++localVar;
    printf("%d\n", localVar); // 2
}

int main(int argc, char const *argv[])
{
    func();
    // main 函数中无法访问 func 函数中的静态局部变量
    return 0;
}
静态全局变量

定义在函数外部,生命周期为程序的整个运行时间,但作用域仅限于定义它的文件(即具有文件内作用域)。

#include <stdio.h>

// 全局静态变量
static int globalVar = 10; // 只在当前文件内可见

int main(int argc, char const *argv[])
{
    printf("%d\n", globalVar); // 10
    return 0;
}
静态变量可见性的底层实现

cc++ 中,静态变量的可见性(作用域和链接性)是通过编译器和链接器的机制来实现的。

分别将上面的两段代码进行编译成汇编代码,并查看代码生成的符号表,如下所示:

  • 静态局部变量代码示例
$ objdump -t test.o 

test.o:     文件格式 elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 test.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .rodata        0000000000000000 .rodata
0000000000000000 l     O .data   0000000000000004 localVar.0
0000000000000000 g     F .text  0000000000000036 func
0000000000000000         *UND*  0000000000000000 printf
0000000000000036 g     F .text  0000000000000024 main

从上面的符号表中可知,localVar.data 初始化数据段,同时显示的符号绑定为 l(local) 本地符号,那么对于后续的链接阶段来说只能看到全局符号 g(global),所以上述代码中的 localVar 只能在本文件内可见。

  • 静态全局变量代码示例
$ objdump -t test.o

test.o:     文件格式 elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 test.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l     O .data  0000000000000004 globalVar
0000000000000000 l    d  .rodata        0000000000000000 .rodata
0000000000000000 g     F .text  0000000000000036 main
0000000000000000         *UND*  0000000000000000 printf

对于静态全局变量来说同理,从符号表中也可以看出 globalVar.data 初始化数据段,也同样显示的符号绑定为 l(local) 本地符号,所以代码中的 globalVar 只能在本文件内可见。

静态变量的初始化

cc++ 中静态变量的初始化机制是一样的,但是对于其中的局部静态变量和全局静态变量来说确实存在差异。

静态局部变量
  • 在程序启动时,静态局部变量的内存空间已经被分配。
  • 静态局部变量的初始化是在第一次执行到变量声明语句时才发生。
  • 初始化只发生一次,无论函数被调用多少次,静态局部变量都不会重新初始化。
静态全局变量
  • 静态全局变量在程序加载时被分配内存,并在程序执行之前初始化。
  • 静态全局变量的初始值要么是显式地由程序员设置,要么是默认初始化(例如整数默认初始化为 0)。
  • 当程序结束时,静态全局变量的生命周期才结束,它们所占用的内存才会被释放。
内存模型

静态变量在程序运行时存储在数据段中。数据段是程序内存布局的一部分,专门用于存储初始化的全局变量和静态变量。

其中数据段分为两个部分:

  • 初始化数据段(Initialized Data Segment,.data:存储有初始值的全局变量和静态变量。
  • 未初始化数据段(BSS Segment,.bss:存储未初始化的全局变量和静态变量,这些变量在程序启动时会被自动初始化为零。

在这里插入图片描述

对象静态成员

c++ 中,类的静态成员属性是一种特殊的成员变量,它与类本身相关,而不是与类的某个具体对象相关。静态成员属性在类的所有对象之间共享,具有独特的内存模型和语义。这个在 c 中是不存在的。

静态成员属性属于类本身,而不是某个对象。因此,它们需要通过static关键字声明,并且通常在类外进行定义和初始化。

class MyClass {
public:
    static int count;  // 静态成员变量声明
};

// 在类外定义并初始化
int MyClass::count = 0;
  • 声明:在类内使用static关键字声明。
  • 定义与初始化:在类外进行定义和初始化。

其中,静态成员变量的内存模型与全局静态变量类似,存储在数据段中。它们的生命周期从程序启动开始,到程序结束时结束。

  • 存储位置:数据段(.data 段或 .bss 段)。
  • 生命周期:从程序启动到程序结束。
  • 初始化:未初始化的静态成员变量会被自动初始化为0nullptr

另外对于访问形式来说,静态成员变量可以通过类名或对象名访问。代码如下所示:

#include <iostream>

class MyClass {
public:
    static int count;  // 静态成员变量
};

int MyClass::count = 0;

int main() {
    std::cout << "Initial count: " << MyClass::count << std::endl;  // 使用类名访问

    MyClass obj;
    obj.count = 10;  // 不推荐通过对象调用的形式访问静态成员属性

    std::cout << "Updated count: " << MyClass::count << std::endl;  // 使用类名访问
    return 0;
}

需要注意的是,在 c++11 标准中,支持类内初始化器对静态常量成员属性直接在类内初始化(但是必须是整形或者枚举类型,否则必须类外初始化),代码如下所示:

#include <iostream>

class MyClass
{
public:
	static const int maxCount = 100;  // 在类内初始化(仅适用于整型和枚举类型)

	void showMaxCount() const
	{
		std::cout << "max count is: " << maxCount << std::endl;
	}
};

int main()
{
	std::cout << "max count: " << MyClass::maxCount << std::endl; // 通过类名直接访问
	MyClass obj;
	obj.showMaxCount();
	return 0;
}

🌺🌺🌺撒花!

如果本文对你有帮助,就点关注或者留个👍
如果您有任何技术问题或者需要更多其他的内容,请随时向我提问。

在这里插入图片描述


http://www.niftyadmin.cn/n/5865221.html

相关文章

unordered_set和unordered_map的使用

Hello&#xff0c;今天我来为大家介绍一下前几年才刚刚新出的两个容器——unordered_map和unordered_set&#xff0c;这两个容器属于是map系列和set系列中的一种&#xff0c;和map/set不同的是它们的底层&#xff0c;map/set的底层是红黑树&#xff0c;而unordered_map/unorder…

【信息系统项目管理师-案例真题】2010下半年案例分析答案和详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一【问题‍ 1】(10‍ 分)‍【问题‍ 2】(8‍ 分)【问题‍ 3】(7‍ 分)‍试题二【问题‍ 1】(10‍ 分)‍【问题‍ 2】(10‍ 分)‍【问题‍ 3】(5‍ 分)‍试题三【问题‍ 1】(10‍ 分)【问题‍ 2】(5‍ 分)‍…

什么是MySql的主从复制(主从同步)?

主页还有其他面试题总结&#xff0c;有需要的可以去看一下&#xff0c;喜欢的就留个三连再走吧~ 1.什么是MySql的主从复制原理&#xff1f; 主从复制的核心就是二进制binlog&#xff08;DDL&#xff08;数据定义语言&#xff09;语句和DML&#xff08;数据操纵语言&#xff09…

005:Cesium.viewer 知识详解、示例代码

查看本专栏目录 - 本文是第 005个API内容详解 vue+cesium 示例教程200+目录 文章目录 一、Cesium.Viewer 知识详解1. 主要用途2. 构造函数与参数3. 常用属性(1)`viewer.scene`(2)`viewer.camera`(3)`viewer.entities`(4)`viewer.clock`4. 常用方法(1)`viewer.zoomTo(…

Websock Demo(二) Java后端代码

1.WebSocket配置类。开启WebSocket的支持 Configuration public class WebSocketConfig {/*** bean注册&#xff1a;会自动扫描带有ServerEndpoint注解声明的Websocket Endpoint(端点)&#xff0c;注册成为Websocket bean。* 要注意&#xff0c;如果项目使用外置的servlet容器&…

【Microsoft® PowerPoint for Mac】MAC一键导出PPT备注

MAC一键导出PPT备注 1.搜索自动操作2.点击快速操作3.搜索并运行AppleScript4.输入代码&#xff0c;并选择只应用于Microsoft PowerPoint for Mac【右上角】5. CRTLS保存为“将备注导出为txt”&#xff0c;PPT中应用。 MAC没自带&#xff0c;需要自己配置 1.搜索自动操作 2.点击…

网页制作08-html,css,javascript初认识のhtml使用框架结构,请先建立站点!

框架一般由框架集和框架组成。 框架集就像一个大的容器&#xff0c;包括所有的框架&#xff0c;是框架的集合。 框架是框架集中一个独立的区域用于显示一个独立的网页文档。 框架集是文件html&#xff0c;它定义一组框架的布局和属性&#xff0c;包括框架的数目&#xff0c;框架…

ES6新增的变量

ES6新增了两个变量&#xff0c;一个是let&#xff0c;另一个是const&#xff0c;接下来我们说一说他们的区别&#xff1f; let/const 与 var 的区别&#xff1f; 1.预解析 var会进行预解析 let/const没有预解析&#xff0c;必须先声明后使用 2.重复变量名 var定义的变量可…