Static VS Const

本文深入探讨了C++中static和const关键字的作用与用法。解析了static如何控制存储方式与可见性,并介绍了const的各种应用场景及其优势。


一、控制存储方式:

  static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间。

  1、引出原因:函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现?
最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。

  2、 解决方案:因此c++ 中引入了static,用它来修饰变量,它能够指示编译器将此变量在程序的静态存储区分配空间保存,这样即实现了目的,又使得此变量的存取范围不变。

二、控制可见性与连接类型 :

  static还有一个作用,它会把变量的可见范围限制在编译单元中,使它成为一个内部连接,这时,它的反义词为”extern”.

  static作用分析总结:static总是使得变量或对象的存储形式变成静态存储,连接方式变成内部连接,对于局部变量(已经是内部连接了),它仅改变其存储方式;对于全局变量(已经是静态存储了),它仅改变其连接类型。
类中的static成员:

三、出现原因及作用:

  1、需要在一个类的各个对象间交互,即需要一个数据对象为整个类而非某个对象服务。

  2、同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。

  类的static成员满足了上述的要求,因为它具有如下特征:有独立的存储区,属于整个类。

四、注意:

  1、对于静态的数据成员,连接器会保证它拥有一个单一的外部定义。静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

  2、类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。


const:

一、const的特性

1. 首先,以const 修饰的常量值,具有不可变性,这是它能取代预定义语句的基础。

2. 第二,很明显,它也同样可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。

3. 第三,c++的编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高,同时,这也是它取代预定义语句的重要基础。这里,我要提一下,为什么说这一点是也是它能取代预定义语句的基础,这是因为,编译器不会去读存储的内容,如果编译器为const分配了存储空间,它就不能够成为一个编译期间的常量了。

4. 最后,const定义也像一个普通的变量定义一样,它会由编译器对它进行类型的检测,消除了预定义语句的隐患。

二、const 使用情况分类详析:

1.const 用于指针的两种情况分析:
 int const *a;  file://a可变,*a不可变
 int *const a;  file://a不可变,*a可变

  分析:const 是一个左结合的类型修饰符,它与其左侧的类型修饰符和为一个类型修饰符,所以,int const 限定 *a,不限定a。int *const 限定a,不限定*a。

2.const 限定函数的传递值参数:

 void fun(const int var);

  分析:上述写法限定参数在函数体中不可被改变。由值传递的特点可知,var在函数体中的改变不会影响到函数外部。所以,此限定与函数的使用者无关,仅与函数的编写者有关。
结论:最好在函数的内部进行限定,对外部调用者屏蔽,以免引起困惑。如可改写如下:

void fun(int var){
const int & varalias = var;

varalias ....

.....

}

3.const 限定函数的值型返回值:

const int fun1();

const myclass fun2();

 分析:上述写法限定函数的返回值不可被更新,当函数返回内部的类型时(如fun1),已经是一个数值,当然不可被赋值更新,所以,此时const无意义,最好去掉,以免困惑。当函数返回自定义的类型时(如fun2),这个类型仍然包含可以被赋值的变量成员,所以,此时有意义。

4. 传递与返回地址: 此种情况最为常见,由地址变量的特点可知,适当使用const,意义昭然。

5. const 限定类的成员函数:

class classname {

 public:

  int fun() const;

 .....

}

  注意:采用此种const 后置的形式是一种规定,亦为了不引起混淆。在此函数的声明中和定义中均要使用const,因为const已经成为类型信息的一部分。

获得能力:可以操作常量对象。

失去能力:不能修改类的数据成员,不能在函数中调用其他不是const的函数。

 

<think>我们讨论的是C/C++中的`const static`和`static const`。首先,需要明确的是,在C/C++中,`const static`和`static const`是等价的,没有区别。它们都表示一个静态的常量(即只读的静态变量)。不过,在书写顺序上,有些人习惯写`static const`,而有些人习惯写`const static`,但编译器将其视为相同。 ### 1. 含义 - **`static`**:表示静态存储期和内部链接(对于全局变量)或静态存储期(对于局部变量)。 - 在函数内部(局部变量):变量在程序运行期间只初始化一次,且生命周期持续到程序结束。每次调用函数时,该变量保持上一次的值。 - 在全局作用域:变量或函数的作用域被限制在当前文件(即内部链接),其他文件无法访问。 - **`const`**:表示变量是只读的,即常量。一旦初始化后,其值不能被修改。 当两者结合时,即`static const`或`const static`,表示一个静态的常量。 ### 2. 使用场景 #### (1) 全局作用域 在全局作用域中,`static const`(或`const static`)用于定义文件作用域内的常量。由于`static`的修饰,该常量只在当前文件可见,避免了与其他文件的命名冲突。同时,`const`确保其值不可修改。 示例: ```c // 在file1.cpp中 static const int MAX_SIZE = 100; // 或 const static int MAX_SIZE = 100; // 在file2.cpp中 extern const int MAX_SIZE; // 错误!无法访问file1.cpp中的MAX_SIZE,因为static使其具有内部链接 ``` #### (2) 局部作用域(函数内部) 在函数内部,`static const`用于定义只初始化一次且不可修改的局部变量。这种变量在程序运行期间一直存在,但只能在函数内部访问。 示例: ```c void func() { static const int local_const = 42; // 初始化只发生一次 // local_const = 43; // 错误,因为const修饰,不可修改 // 每次调用func,local_const都是42,且不会重新初始化 } ``` #### (3) 类成员(C++) 在C++中,`static const`可以用于类的静态常量成员。此时,该成员属于整个类,而不是某个对象。它必须在类外定义(除非是整型或枚举类型,且C++11后允许在类内初始化)。 示例: ```c++ class MyClass { public: static const int MAX = 100; // 声明,如果是整型常量,可以在类内初始化(C++11) }; // 在类外定义(如果需要在类外分配存储空间,则必须定义) const int MyClass::MAX; // 如果类内已初始化,这里可以不带初始化值,但通常还是需要定义(有些编译器要求) ``` 注意:在C++中,`const static`的写法也是可以的,但通常使用`static const`。 ### 3. 与单独使用`const`或`static`的区别 - **单独使用`static`(非`const`)**:变量是静态的,但值可以修改(非常量)。 - **单独使用`const`(非`static`)**: - 在全局作用域:默认具有外部链接(除非在匿名命名空间),即其他文件可以通过`extern`声明来访问。但在C++中,全局`const`变量默认具有内部链接(除非用`extern`显式指定外部链接)。 - 在局部作用域:每次函数调用都会重新初始化,且值不可修改,但生命周期仅限于函数调用期间(实际上,由于是常量,编译器可能将其优化为立即数,不占用栈空间)。 ### 4. 内存存储 - 对于全局的`static const`:通常存储在只读数据段(`.rodata`)或直接嵌入代码中(作为立即数)。 - 对于局部的`static const`:存储在静态存储区,但只初始化一次,且不可修改。 ### 5. 注意事项 - **初始化**:`static const`必须在声明时初始化(因为`const`要求初始化,且`static`要求只初始化一次)。 - **C与C++的差异**:在C中,全局`const`变量默认具有外部链接,而C++中默认具有内部链接(因此C++中全局`const`变量相当于隐式加了`static`)。但为了代码清晰,建议显式使用`static`。 ### 示例代码 ```c // C++示例:文件作用域 static const int g_value = 10; // 文件内可见,不可修改 void foo() { static const int local_value = 20; // 静态常量,只初始化一次 // ... } // C++类成员 class Test { public: static const int MAX = 100; // 类内声明(整型常量) }; const int Test::MAX; // 类外定义(有些编译器要求,即使类内已初始化) ``` ### 相关问题 1. 在C++中,为什么有时候需要在类外定义静态常量成员? 2. `static const`成员变量和`constexpr`成员变量有什么区别? 3. 如何在不同文件之间共享常量定义(即具有外部链接的常量)? 4. 在C++中,全局`const`变量默认的内部链接是如何影响程序的?</think>### `const static` 与 `static const` 详解 在 C/C++ 中,`const static` 和 `static const` **本质相同**,两者无功能差异。编译器会将其视为同一种声明,区别仅在于关键字顺序(书写习惯)。以下是核心知识点: --- ### 一、核心含义 #### 1. **`static` 的作用** - **存储期控制**: 变量在程序整个生命周期存在(存储在静态存储区),而非栈或堆[^1]。 - **作用域控制**: - **全局变量/函数**:限制作用域为当前文件(内部链接) - **局部变量**:保持值在函数调用间持久化 - **类成员**:属于类而非实例(所有对象共享) #### 2. **`const` 的作用** - **只读性**:变量初始化后不可修改 - **编译期检查**:防止意外写入(如 `str[4]='x'` 会触发编译错误)[^4] #### 3. **组合效果** `static const` 或 `const static` 表示: - **静态存储**(程序生命周期) - **只读属性**(不可修改) - 作用域由声明位置决定 --- ### 二、使用场景与示例 #### 1. **全局常量(文件作用域)** ```c++ // File: config.cpp static const int MAX_TEMP = 150; // 文件内可见,外部无法链接 // 等效写法:const static int MAX_TEMP = 150; ``` - **作用**:避免全局命名冲突,作为文件私有常量 - **内存**:存储在只读数据段(`.rodata`) #### 2. **函数内持久化常量** ```c++ void read_sensor() { static const float CALIBRATION_FACTOR = 1.023f; // 只初始化一次 // CALIBRATION_FACTOR = 1.1f; // 错误:const禁止修改 } ``` - **特点**: - 首次调用时初始化,后续调用保留值 - 线程安全(C++11 起保证初始化线程安全) #### 3. **类静态常量(C++)** ```c++ class TemperatureMonitor { public: static const int SAFE_LIMIT = 85; // 声明(整型可直接初始化) }; // 类外定义(非整型或需取地址时必需) const int TemperatureMonitor::SAFE_LIMIT; ``` - **用途**:所有对象共享的类级别常量 - **限制**: - C++ 中仅整型(`int`, `char` 等)可在类内直接初始化 - 非整型需在类外定义(如 `static const double PI;`) --- ### 三、关键区别对比 | 特性 | 单独 `static` | 单独 `const` | `static const`/`const static` | |---------------------|-----------------------|-----------------------|-------------------------------------| | **存储位置** | 静态存储区 | 栈或常量区 | 静态存储区(只读段) | | **生命周期** | 程序整个生命周期 | 作用域结束时销毁 | 程序整个生命周期 | | **修改权限** | 可修改 | **不可修改** | **不可修改** | | **多文件共享** | 需 `extern` 声明 | 默认内部链接(C++) | 文件内私有(`static` 作用) | | 典型用例 | 计数器、缓存 | 函数参数保护 | 配置常量、数学常数 | --- ### 四、实际应用建议 1. **优先使用 `static const`** - 统一书写顺序(业界惯例:`static const`) - 例:`static constexpr auto PI = 3.14159;`(C++11 起) 2. **避免全局非 `static` 常量** ```c++ // 不推荐(C++中默认内部链接,但C中为外部链接) const int GLOBAL_CONST = 100; // 推荐:显式控制作用域 static const int FILE_SCOPED_CONST = 100; ``` 3. **C 与 C++ 差异处理** - **C 语言**:全局 `const` 默认外部链接,需加 `static` 限制作用域 - **C++**:全局 `const` 默认内部链接,`static` 可省略(但显式添加更清晰) --- ### 五、相关问题 1. `static const` 成员变量在 C++ 中为什么需要类外定义? 2. 如何在不同 C++ 文件间共享常量定义? 3. `constexpr` 和 `static const` 在性能上有何差异? 4. 多线程环境下使用静态局部常量是否安全? > 通过合理使用 `static const`,可提升代码安全性(`const`)并优化资源管理(`static`),是嵌入式系统和性能敏感场景的常用技术[^1][^2][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值