C++的次语言:
C++的编译流程:
C++代码的编译流程通常包括了多个阶段,从源代码到可执行程序的生成。下面是一个简要的C++代码编译流程的概述:
1. 预处理(Preprocessing):
- 在这个阶段,编译器会处理所有的预处理指令,例如 `#include`、`#define` 等,以及删除注释。
- 预处理指令的处理会生成一个经过预处理的源代码文件。
2. 编译(Compilation):
- 经过预处理的源代码会被编译器转换为汇编语言代码(通常是中间表示形式)。
- 编译阶段主要负责检查语法错误和类型错误,并生成对应的中间表示文件。
3. 汇编(Assembly):
- 在这个阶段,汇编器将中间表示的代码转换为机器代码,生成目标文件(通常是以 `.obj` 或 `.o` 为扩展名)。
- 目标文件包含了计算机可执行的二进制代码和相关的元信息。
4. 链接(Linking):
- 当你的程序使用了多个源文件或库文件时,这些目标文件需要被链接在一起,生成最终的可执行程序。
- 链接器会解决函数调用、变量引用等,并将不同目标文件中的代码和数据合并。
- 最终的可执行文件就是由链接器生成的。
5. 加载(Loading)(可选):
- 如果你的操作系统需要,可执行文件会被加载到内存中,准备运行。
- 这一步骤通常由操作系统完成。
6. 运行(Execution):
- 可执行程序在内存中运行,执行其中的代码,产生相应的计算结果。
需要注意的是,这个流程可能在不同的编译器和操作系统上有所不同。另外,现代的编译器和开发环境通常会在这些阶段中进行优化,以提高代码的性能和效率。
#define PI 3.14159
static
关键字来定义,因为它们属于类而不是类的实例。定义为 static
的常量将在所有类的实例之间共享,且只存在一份副本,可以节省内存。#include
class MyClass {
public:
static const int classConstant = 42; // 类专属常量
static const double pi; // 声明,定义在类外部
void printClassConstant() {
std::cout << "Class constant: " << classConstant << std::endl;
}
};
const double MyClass::pi = 3.1415926; // 在类外部定义类专属常量
int main() {
MyClass obj;
obj.printClassConstant(); // 调用类专属常量的成员函数
std::cout << "Pi: " << MyClass::pi << std::endl; // 通过类名访问类专属常量
return 0;
}
//错误的,ConstNumber 虽然是类的静态常量,但是它在编译期是无法确定的,因此不能用作数组大小。
class ANonDefine
{
public:
static const int ConstNumber;
int Array[ConstNumber];
};
解决方法:
在ConstNumber声明时就赋值。
使用enum
class ANonDefine
{
public:
enum {ArraySize=5};
int Array[ArraySize];
};
#include
#define MAX_MACRO(a, b) ((a) >= (b) ? (a) : (b))
inline int max_inline(int a, int b) {
return (a >= b) ? a : b;
}
int main() {
int x = 5, y = 6;
int result_macro = MAX_MACRO(++x, y); // 使用宏,产生不同的结果
x = 5; y = 6; // 正确的变量赋值
int result_inline = max_inline(++x, y); // 使用内联函数,产生不同的结果
std::cout << "Macro result: " << result_macro << std::endl; //7
std::cout << "Inline result: " << result_inline << std::endl;//6
system("pause");
return 0;
}
// const出现在*左边,表示被指物是常量,出现在*右边,表示指针自身是常量
const int x = 5; // 声明一个不可修改的整数常量
const int* ptr = &x; // 声明一个指向常量的指针,指针指向的常量不可修改
int const * ptr = &x; // 声明一个指向常量的指针,指针指向的常量不可修改
int y = 10;
int* const ptr = &y; // 声明一个指针常量,指针不可修改
const int* const ptr = &y; // 指针及其指向的常量都不可修改
std::vector<int>Vector;
for(int i=0;i<10;++i)
{
Vector.push_back(i);
}
const std::vector<int>::iterator Iterator=Vector.begin();
*Iterator=10;//所指物可以修改
//Iterator++;迭代器不可修改
std::vector<int>::const_iterator ConstIterator=Vector.begin();
//*ConstIterator=10;所指物不可修改
ConstIterator++;//指针可以修改
for (auto i=ConstIterator;i!=Vector.end();++i)
{
FFunctionLibrary::Println(*i);
}
#include
class MyClass {
public:
void printValue() {
std::cout << "Non-const function: " << value << std::endl;
}
void printValue() const {
std::cout << "Const function: " << value << std::endl;
}
void setValue(int newValue) {
value = newValue;
}
private:
int value = 0;
};
int main() {
MyClass obj;
const MyClass constObj;
obj.setValue(42);
obj.printValue(); // 调用非常量成员函数
constObj.printValue(); // 调用常量成员函数
return 0;
}
class MyClass {
public:
int getValue() const; // 声明常量成员函数
private:
mutable int count; // 声明一个可变成员变量
};
int MyClass::getValue() const {
// 在常量成员函数内修改可变成员变量
count++;
return count;
}
const int& operator[](int index)const
{
return IntNumber;
}
int& operator[](int index)
{
//return IntNumber;
return const_cast<int&>(static_cast<const Const&>(*this)[index]);
}
//file1.cpp
#include
int getGlobalValue();
int main() {
std::cout << "Global value from File1: " << getGlobalValue() << std::endl;
return 0;
}
//file2.cpp
#include
int getGlobalValue() {
static int value = 42; // 局部静态变量,仅在首次调用时初始化
return value;
}
在这个示例中,File1.cpp 和 File2.cpp 是两个不同的编译单元。File1.cpp 中的 main 函数调用了 getGlobalValue 函数,而 getGlobalValue 函数在 File2.cpp 中定义,返回一个局部静态变量。由于局部静态变量的初始化仅在首次调用时进行,因此不需要担心初始化顺序的问题,从而避免了编译单元之间的依赖。