C++程序生命周期

发布于 2023-04-26 | 作者: 许糖豆 | 来源: CSDN博客 | 转载于: CSDN博客

C/C++ 程序的生命周期

g++ –E hello.cpp -o hello.i //将hello.c预处理输出hello.i
g++ -S hello.i -o hello.s //将预处理输出文件hello.i汇编成hello.s文件
g++ -c hello.i -o hello.o //将预处理输出文件hello.i汇编成hello.s文件
g++ hello.o -o hello //将预处理输出文件hello.i汇编成hello.s文件

1. 预处理阶段

1.1. #define 预处理

#define macro-name replacement-text
#include <iostream>
using namespace std;
 
#define PI 3.14159
 
int main ()
{
    cout << "Value of PI :" << PI << endl; 
 
    return 0;
}

现在,让我们测试这段代码,看看预处理的结果。假设源代码文件已经存在,接下来使用 -E 选项进行编译,并把结果重定向到 test.p

$ gcc -E test.cpp > test.p
...
int main ()
{ 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

1.2. 参数宏定义

#include <iostream>
using namespace std;
 
#define MIN(a,b) (a<b ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
   cout <<"较小的值为:" << MIN(i, j) << endl;
 
    return 0;
}

1.3. 条件编译

#include <iostream>
using namespace std;
#define DEBUG
 
#define MIN(a,b) (((a)<(b)) ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif
 
#if 0
   /* 这是注释部分 */
   cout << MKSTR(HELLO C++) << endl;
#endif
 
   cout <<"The minimum is " << MIN(i, j) << endl;
 
#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif
    return 0;
}
#ifdef NULL
   #define NULL 0
#endif

1.4. # 和 ## 运算符

#include <iostream>
using namespace std;
 
#define MKSTR( x ) "first"#x


#define CLASS_NAME(name) aaa##name
#define MERGE(x,y) x##y##x

char aaaTimer[] = "this is aaaTimer";
int meTome = 10;

int main ()
{
    cout << MKSTR(HELLO C++) << endl;

    cout <<  CLASS_NAME(Timer) << endl;    

    cout <<  MERGE(me,To) << endl;   
    
    return 0;
}
-> % ./a.out         
firstHELLO C++
this is aaaTimer
10

2. 编译阶段

2.1. 静态断言(static_assert)

它是编译阶段里检测各种条件的“断言”,编译器看到 static_assert 也会计算表达式的值,如果值是 false,就会报错,导致编译失败。 static_assert 是“静态断言”,在编译阶段计算常数和类型,如果断言失败就会导致编译错误。它也是迈向模板元编程的第一步。
比如说,这节课刚开始时的斐波拉契数列计算函数,可以用静态断言来保证模板参数必须大于等于零:

char* p = nullptr;
static_assert(p == nullptr, "some error.");  // 错误用法

2.2. 动态断言

它用来断言一个表达式必定为真。比如说,数字必须是正数,指针必须非空、函数必须返回 true

assert(i > 0 && "i must be greater than zero");
assert(p != nullptr);
assert(!str.empty());

assert 的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。
使用 assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含 #include 的语句之前插入 #define NDEBUG 来禁用 assert 调用,示例代码如下