单独编译
链接编译模块时,需确保所有对象文件或库都是由同一个编译器生成的
因为不同编译器可能用不同方式实现名称修饰
1 2 3 4 5 6 7 8 9 10 11 12
| #ifndef RECTANGLE_H #define RECTANGLE_H
struct Rectangle { int length; int width; };
void printRectangle(const Rectangle& r);
#endif
|
1 2 3 4 5 6 7
| #include <iostream> #include "Rectangle.h"
void printRectangle(const Rectangle& r) { std::cout << "Length: " << r.length << ", Width: " << r.width << '\n'; }
|
1 2 3 4 5 6 7 8
| #include <iostream> #include "Rectangle.h"
int main() { Rectangle r{10, 5}; printRectangle(r); return 0; }
|
执行 g++ Lab.cpp Rectangle.cpp 后会发生如下:
预处理器将包含的文件与源代码文件合并,产生临时文件temp1.cpp和temp2.cpp
编译器生成每个源代码文件的目标代码文件Lab.o和Rectangle.o
链接程序将目标代码文件、库代码和启动代码合并,生成可执行文件a.out
存储持续性、作用域和链接性
自动存储持续性:函数定义中声明的变量,出了定义域就自动释放
静态存储持续性:函数定义外定义的变量和static修饰的变量,在程序整个运行过程中都存在
线程存储持续性(C++11):thread_local修饰的变量,生命周期和所属线程一样长
动态存储持续性:用new分配的内存将一直存在,直到用delete释放或程序结束
自动变量没有链接性
静态变量有外部链接性(可在其他文件中访问),内部链接性(只能在当前文件中访问)和无链接性(只能在当前函数或代码块中访问)
注意static用于局部声明时,表示存储持续性,用于代码块外的声明时,表示内部链接性
1 2 3 4 5 6 7 8
| int global = 1000; static int one_file = 50; void f() { static int count = 0; } int main() { .. }
|
extern 关键字
引用声明其他文件的外部变量,不分配存储空间,且不进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream>
extern int lab2; extern void printlab2();
int main() { std::cout << lab2 << '\n'; lab2 = 5; printlab2(); std::cout << lab2 << '\n'; return 0; }
|
1 2 3 4 5 6 7 8
| #include <iostream>
int lab2 = 2;
void printlab2() { std::cout << lab2 << '\n'; }
|
在变量前面加上::可以显式地使用该变量的全局版本
1 2 3 4 5 6 7 8 9
| #include <iostream>
int x = 5;
int main() { int x = 1; std::cout << ::x << ' ' << x << '\n'; return 0; }
|
两个文件中有一个同名的外部变量,将无法通过编译
需将其中一个加上static,静态变量将隐藏外部变量
说明符和限定符
volatile关键字表明变量的内存单元即使没有被代码修改,其值也可能改变(由于硬件),告诉编译器不要进行神秘的优化
mutable关键字指出即使结构或变量为const,其某个成员也可被修改(珂朵莉树有用到来着)
const全局变量的链接性为内部的(就是说const全局定义蕴含了static),想要其链接性为外部必须显式地用extern关键字,其他文件也必须用extern来引用声明
函数和链接性
函数都默认是静态持续,外部链接性的,也可用static显示定义为内部链接的
namespace
namespace可以是全局的,也可以在另一个namespace里,但不能在代码块里
在namespace里声明的名称的链接性默认为外部的
namespace是开放的,可以一段一段写
指导原则
用namespace里声明的变量,而不是外部全局变量和静态全局变量
1 2 3 4 5 6 7 8 9 10 11
| #ifndef CONFIG_H #define CONFIG_H
namespace AppConfig { extern int screenWidth; extern int screenHeight; }
#endif
|
1 2 3 4 5 6 7 8
| #include "config.h"
namespace AppConfig { int screenWidth = 800; int screenHeight = 600; }
|
1 2 3 4 5 6 7 8 9
| #include <iostream> #include "config.h"
int main() { std::cout << "Screen Width: " << AppConfig::screenWidth << std::endl; std::cout << "Screen Height: " << AppConfig::screenHeight << std::endl; return 0; }
|