C Plus Plus预处理器

顾名思义,预处理器是在编译之前处理我们的源代码的程序。 在C/C++中编写程序和执行程序之间涉及许多步骤。在实际开始学习预处理器之前,让我们看一下这些步骤。

C/C Plus Plus预处理器

您可以在上图中看到中间步骤。程序员编写的源代码存储在文件program.c中。然后,该文件由预处理器处理,并生成名为program的扩展源代码文件。该扩展文件由编译器编译,并生成一个名为program .obj的目标代码文件。最后,链接器将此目标代码文件链接到库函数的目标代码,以生成可执行文件program.exe。

预处理程序提供预处理程序指令,这些指令告诉编译器在编译之前对源代码进行预处理。所有这些预处理程序指令均以“#”(哈希)符号开头。C/C++程序中语句开头的(#)符号表示它是预处理程序指令。我们可以将这些预处理程序指令放置在程序中的任何位置。 一些预处理器指令的示例包括:#include,#define,#ifndef等。

预处理器指令有4种主要类型:

  • 文件包含
  • 条件编译
  • 其他指令

现在让我们详细了解这些指令中的每一个。

1.

宏(Macros):宏是程序中的一段代码,具有一定的名称。只要编译器遇到此名称,编译器就会用实际的代码段替换该名称。“ #define”指令用于定义宏。现在让我们借助程序来了解宏定义:

<code>#include <iostream> 

// macro definition
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
std::cout << i << "\\n";
}

return 0;
} /<iostream>/<code>

输出:

<code>0
1
2
3
4/<code>

在上述程序中,编译器执行LIMIT时,将其替换为5。宏定义中的LIMIT称为宏模板,而5则是宏扩展。

注意:宏定义的末尾没有分号(';')。宏定义不需要以分号结尾。

带参数的宏:我们还可以将参数传递给宏。用参数定义的宏的作用类似于函数。 让我们通过一个程序来理解这一点:

<code>#include <iostream> 

// macro with parameter
#define AREA(l, b) (l * b)
int main()
{
int l1 = 10, l2 = 5, area;

area = AREA(l1, l2);

std::cout << "Area of rectangle is: " << area;

return 0;
} /<iostream>/<code>

输出:

<code>Area of rectangle is: 50/<code>

从上面的程序中我们可以看到,只要编译器在程序中找到AREA(l,b),它就会用语句(l * b)替换它。不仅如此,传递给宏模板AREA(l,b)的值还将在语句(l * b)中替换。因此,AREA(10,5)等于10 * 5。

2. 文件包含:这种类型的预处理程序指令告诉编译器在源代码程序中包含文件。 用户可以在程序中包括两种类型的文件:

1)头文件或标准文件:这些文件包含预定义函数的定义,例如printf(),scanf()等。必须包含这些文件才能使用这些函数。不同的函数在不同的头文件中声明。 例如,标准I/O功能位于“ iostream”文件中,而执行字符串操作的函数位于“ string”文件中。

语法:

<code>#include< file_name >/<code>

其中file_name是要包含的文件的名称。 “ ”括号告诉编译器在标准目录中查找文件。

2) 用户定义的文件:当程序变得很大时,将其分成较小的文件并在需要时包括在内是一个很好的做法。这些类型的文件是用户定义的文件。这些文件可以包括为:

<code>#include"filename"/<code>

3. 条件编译:条件编译指令是指令的类型,可帮助根据某些条件编译程序的特定部分或跳过程序某些特定部分的编译。这可以通过两个预处理命令“ ifdef”和“endif”来完成。

语法:

<code>#ifdef macro_name
statement1;
statement2;
statement3;
.
.
.
statementN;
#endif/<code>

如果定义了名称为“ macroname”的宏,则该语句块将正常执行,但如果未定义,则编译器将直接跳过该语句块。

4. 其他指令:除了上述指令外,还有另外两个不常用的指令。这些是:

1) #undef指令:#undef指令用于取消定义现有的宏。该指令的工作方式如下:

<code>#undef LIMIT/<code>

使用此语句将取消定义现有的宏LIMIT。在此语句之后,每个“ #ifdef LIMIT”语句将评估为false。

2) #pragma指令:此指令是一种特殊用途的指令,用于打开或关闭某些功能。这种类型的指令是特定于编译器的,即它们随编译器的不同而不同。下面讨论了一些#pragma指令:

#pragma startup#pragma exit:这些指令可帮助我们指定程序启动之前(控件传递到main()之前)和程序退出之前(控件从main()返回之前)所需运行的功能。

注意:以下程序不适用于GCC编译器。

看下面的程序:

<code>#include <stdio.h> 

void func1();
void func2();

#pragma startup func1
#pragma exit func2

void func1()
{
printf("Inside func1()\\n");
}

void func2()
{
printf("Inside func2()\\n");
}

int main()
{
void func1();
void func2();
printf("Inside main()\\n");

return 0;
} /<stdio.h>/<code>

输出:

<code>Inside func1()
Inside main()
Inside func2()/<code>

当在GCC编译器上运行时,以上代码将产生如下输出:

<code>Inside main()/<code>

发生这种情况是因为GCC不支持#pragma启动或退出。 但是,您可以将以下代码用于GCC编译器上的类似输出。

<code>#include <stdio.h> 

void func1();
void func2();

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();

void func1()
{
printf("Inside func1()\\n");
}

void func2()
{
printf("Inside func2()\\n");
}

int main()
{
printf("Inside main()\\n");

return 0;
} /<stdio.h>/<code>

#pragma warn指令:该指令用于隐藏在编译过程中显示的警告消息。

我们可以隐藏警告,如下所示:

  • #pragma warn -rvl:该指令隐藏那些本应返回值的函数未返回值时发出的警告。
  • #pragma warn -par:该指令隐藏当函数不使用传递给它的参数时引发的警告。
  • #pragma warn -rch:此指令隐藏当代码不可访问时发出的警告。例如:在函数的return语句之后编写的任何代码均不可访问。


分享到:


相關文章: