@@ -58,9 +58,9 @@ std::cout << R"+*(("hello") \n world)+*" << std::endl;
58
58
59
59
可以将一个指针指向某个硬件位置,其中包含了来自串行端口的时间或信息。在这种情况下,硬件(而不是程序)可能修改其中的内容。或者两个程序可能互相影响,共享数据。[[ ref]] ( https://www.runoob.com/w3cnote/c-volatile-keyword.html )
60
60
61
- 编译器通常可能对某个变量进行优化,比如变量值** 缓存在寄存器中** ,程序在几条语句中多次使用了某个变量的值,则可能会直接使用寄存器中的值。这种优化假设变量的值不会被当前程序之外的程序进行修改 。
61
+ 如果对上面有关嵌入式的知识不太了解也没关系,我再举一个线程的例子。 编译器通常可能对某个变量进行优化,比如变量值** 缓存在寄存器中** ,程序在几条语句中多次使用了某个变量的值,则可能会直接使用寄存器中的值。而另一个线程可能使用的是内存中的值,这样会导致两边不一致。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值 。
62
62
63
- 正如前面所说的,改变这个值的可能不是程序本身,所以可以将变量声明为volatile,相当于告诉编译器,不要进行这种优化 。
63
+ 当然,线程这个例子是一个不太恰当的例子,因为多线程访问同一变量时,我们都会有读锁或者写锁进行保护 。
64
64
65
65
## 5. mutable
66
66
可以用它来指出,即使结构或类变量为const,其某个成员也可以被修改。编译器可以在实际定义之后进行再链接
@@ -72,28 +72,22 @@ const data d {0};
72
72
d.access = 1;
73
73
```
74
74
75
- ## 6. 链接性和持续性
75
+ ## 6. static
76
76
77
- 这里涉及的知识点是链接性(linkage),当使用extern声明,变量将变为外部链接性。<span id="linkage"></span>
78
-
79
- 
80
-
81
-
82
- 函数的链接性呢?C++不允许在一个函数中定义另外一个函数,因此所有函数的存储持续性都自动为**静态**的,即在整个程序执行期间都一直存在;并且链接性是**外部**的,即可以在文件间共享,所以上面例子中我们不需要对一个函数声明`extern`。
77
+ 静态(static)具有三个特性:
78
+ 1. 只执行一次
79
+ 2. 线程安全(C++11)
80
+ 3. 存在全局存储区
83
81
84
- ## 7. static
85
82
上面图说明虽然静态变量static在整个程序执行期间都存在,但它意味着在
86
83
1. 使用关键字static定义的全局变量的作用域为整个源文件,但是不能用于其他源文件(内部链接性)。定义在头文件则可以被导入到不同源文件。
87
84
2. 在代码块中使用关键字static定义的变量被限制在该代码块内(局部作用域、无链接性)。
88
85
3. 如果定义在[类](cpp-class.md)内部,则可在同类的多个对象之间实现数据共享。
89
86
90
87
需要明白,static变量不同于自动变量的是,虽然两者都需要在作用域范围内才能使用,但自动变量脱离作用域后便被回收,而static则是直到程序停止运行后才被回收。
91
88
92
- ### 7.1 局部静态
93
- 局部静态(local static)具有两个特性:
94
- 1. 只执行一次
95
- 2. 线程安全(C++11)
96
-
89
+ ### 6.1 局部静态
90
+ 根据静态的特性,使得局部静态的情况下会出现如下情况,
97
91
```cpp
98
92
struct Data { int x; };
99
93
@@ -127,8 +121,15 @@ int main() {
127
121
}
128
122
```
129
123
124
+ ## 7. 链接
125
+ 链接这个概念和编译过程有关,首先编译器会对源文件(` .cpp ` )进行编译并生产目标文件(` .o ` ),如果有多个源文件,就会生成多个目标文件。然后就会进入链接阶段,把多个目标文件整合成一个可执行文件(` .exe ` ),之所以叫链接,是因为其中一个目标文件中调用的某个函数,它的实现可能在另一个目标文件里,所以要把这个目标文件和另一个目标文件进行链接。
126
+
127
+ 链接的基础在于声明。能够进行链接的前提是能够进行声明,先有了声明,使用了声明,才能在链接阶段通过声明找到实现或定义。所以声明一个函数,也可以说作是使一个函数具备链接能力。
128
+
129
+ 具体的编译过程会在编译章节里面说明,这里先提出链接是因为和后面讲到的extern有些关系。
130
+
130
131
## 8. extern
131
- 关键字extern用于声明一个全局变量。你可以预先声明一个全局变量,相当于作为一个占位符,它允许你延迟定义一个变量 。
132
+ 关键字extern用于 ** 声明 ** 一个 ** 全局变量 ** 。注意是声明而不是定义,函数只要不实现函数体就可以预先声明,但变量的声明和定义通常是同时进行的,比如 ` int a; ` ,虽然没有赋值,但已经定义了一个 ` a ` 变量。 ` extern ` 关键字使得我们可以在任何作用域下声明变量,条件是这个变量在之后必须定义为全局变量 。
132
133
``` cpp
133
134
int main (){
134
135
{
@@ -139,7 +140,7 @@ int main(){
139
140
140
141
int gg = 9 ;
141
142
```
142
- 上面的例子gg的定义在main函数的后面,理论上,是不能在main里面使用gg的,但我们可以使用通过` extern int gg ` 声明gg是一个全局变量。除此之外,你还能用extern预声明一个全局函数。
143
+ 上面的例子gg的定义在main函数的后面,理论上,是不能在main里面使用gg的,但我们可以使用通过` extern int gg ` 声明gg是一个全局变量。除此之外,你还能用extern预声明一个全局函数,但函数本身就是可以声明的,这个用法有点鸡肋 。
143
144
``` cpp
144
145
int main () {
145
146
extern int test();
@@ -152,9 +153,11 @@ int test() {
152
153
}
153
154
```
154
155
155
- 再举个例子,我在file1.cpp 定义了一个变量` x ` ,而file2.cpp中想访问到这个变量,我们该怎么办?在python中直接使用import模块即可,但c++中你只能include一个` .h ` 文件。
156
+ 既然谈到了声明,是不是说明它也具备链接性。答案是肯定的,我们在头文件中用` extern ` 声明变量,随着这个头文件被导入到不同的源文件中,使得该变量在不同源文件中被定义或使用。
157
+
158
+ 我在file1.cpp 定义了一个变量` x ` ,而file2.cpp中想访问到这个变量,我们该怎么办?
156
159
157
- 所以我们需要以` .h ` 文件作为中间人,在其中用` extern ` ** 声明** 该变量,使得它成为全局变量 。注意这里仅仅是声明,而不是定义,说明并未分配存储空间 。
160
+ 所以我们需要以` .h ` 文件作为中间人,在其中用` extern ` ** 声明** 该变量。注意这里仅仅是声明,而不是定义,并未分配存储空间 。
158
161
``` cpp
159
162
#ifndef HELLOWORLD_CH06_H
160
163
#define HELLOWORLD_CH06_H
@@ -213,7 +216,7 @@ int a = 1; // don't do this
213
216
```
214
217
头文件里定义全局变量或函数(inline除外),一旦头文件被导入不同的cpp文件里,则会导致重复重复定义的问题。而使用extern只是声明,编译器允许重复声明。
215
218
216
- 如果想在头文件定义全局变量或函数,建议使用static,static具有只定义一次的特点,目前还未清楚编译器是如何处理的,但经过测试可知不会发生重复定义问题 。
219
+ 如果想在头文件定义全局变量或函数,可以将其定义static,因为static具有只执行一次的特点。编译器发现这个静态变量已经定义过了,就不会继续定义,便不会报multiple definition错误 。
217
220
``` cpp
218
221
// def.h
219
222
#ifndef DEF
@@ -235,7 +238,7 @@ extern还有一个作用通过声明`extern "C" { }`来把函数编译和链接
235
238
// cmax.h
236
239
#ifndef C_MAX_H
237
240
#define C_MAX_H
238
- extern int max(int x, int y);
241
+ int max(int x, int y);
239
242
#endif
240
243
241
244
// cmax.c
@@ -318,7 +321,7 @@ using namespace Jill;
318
321
```
319
322
320
323
### 9.1 使用命名空间的完整例子
321
- 按照惯例,现在头文件中定义命名空间。同时对于命名空间中的变量,若想产生外部链接 ,需要声明为` extern ` 。
324
+ 按照惯例,现在头文件中定义命名空间。同时对于命名空间中的变量,为了避免重复定义 ,需要声明为` extern ` 。
322
325
``` cpp
323
326
#ifndef HELLOWORLD_CH07_H
324
327
#define HELLOWORLD_CH07_H
0 commit comments