c++ 预处理和预处理命令

本文详细介绍了C++预处理器的功能及使用方法,包括预处理命令、条件编译、宏定义与取消定义、文本宏替换、错误指令等核心概念。同时,还提供了多个实例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

预处理器

预处理发生在编译之前,预处理输出的是一个单一的文件,这个文件被送到编译器,进行编译。

预处理命令

每条预处理命令都控制预处理器的行为。每条预处理命令占据一行,有以下的格式:

* # character
* 预处理命令(one of define, undef, include, if, ifdef, ifndef, else, elif, endif, line, error, pragma)
* 参数
* 换行符

条件编译命令

预处理命令可以条件编译源程序的某一部分。指令包括:

#if expression      
#ifdef expression       
#ifndef expression      
#elif expression        
#else       
#endif  

expression must be const expression

Example

#define ABCD 2
#include <iostream>
int main(){
#ifdef ABCD
    std::cout<<"1: yes\n";
#else
    std::cout<<"1: no\n";
#endif

#ifndef ABCD
    std::cout<<"2: no1\n";
#elif ABCD==2
    std::cout<<"2: yes\n";
#else
    std::cout << "2: no2\n";
#endif

#if !defined(DSDE) && (ABCD < 2*4 - 3)
    std::cout<<"3: yes\n";
#endif
}
//output:
//1: yes
//2: yes
//3: yes

替换文本宏命令

语法:

#define identifier replacement-list(optional)   (1) 
#define identifier( parameters ) replacement-list   (2) 
#define identifier( parameters, ... ) replacement-list  (3) (since C++11)
#define identifier( ... ) replacement-list  (4) (since C++11)
#undef identifier   (5) 

#define

不能重复定义相同的宏,否则,编译会报错。但是,如果重复定义的宏完全相同,则,没有任何问题。

object-like macro

(1)的形式。

function-like macro

(2)(3)(4)的形式

(2) 参数个数固定

(3)(4) 可变参数个数,参数能够被访问通过:VA_ARGS

# and ## operators

#被用在replacement-list 中,放在变量前,目的是字符串化该变量。生成的结果是“...”。

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")

##用来连接两个identifier

#include <iostream>

#define FUNCTION(name, a) int fun_##name(){return a;}
FUNCTION(abcd, 12)
FUNCTION(fff, 2)
FUNCTION(qqq, 23)
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout<<#a<<std::endl;

int main()
{
    std::cout << "abcd: " << fun_abcd() << '\n';
    std::cout << "fff: " << fun_fff() << '\n';
    std::cout << "qqq: " << fun_qqq() << '\n';
    std::cout << FUNCTION << '\n';
    OUTPUT(million);               //note the lack of quotes
}

#include命令

include其他源文件到当前文件中,并且,放在该指令之后。语法:

#include <filename> (1) 
#include "filename" (2) 

#include 搜索文件的路径为:standard include directories 。标准c库和c++库的目录都被加入到了standard include directories。standard include directories 通常通过编译选项来定义。如果在standard include directories没有搜索到该文件,程序将会报错。

#include "filename" 搜索文件的路径为: 先在当前文件所在目录下搜索,如果没有搜索到,将在standard include directories下搜索。如果,都没有搜索到,程序报错。

注意问题:

一个文件可能被重复Include,或者递归地include, 为了避免这个问题,通常要在include的文件中,加入一些预处理命令(通常是头文件)。

#ifndef FOO_H_INCLUDED /* any name uniquely mapped to file name */
#define FOO_H_INCLUDED
// contents of the file are here
#endif

Example:

#ifndef TEXT
#define TEXT
#include __FILE__
int main(){
//如果不防止重复include该文件,将会不停include文件,程序ill
}
#endif

Error 命令

语法:

#error error_message    

用于对编译前的检测,程序遇到error,就会停止编译。

编译器自定义指令

语法: #pragma pragma_paramsC++ 标准不包含这些指令,但是编译器厂商会根据自己的需要,定义自己的指令。如果程序遇到不认识的#pragma指令,会直接跳过,不会报错。

改变文件名和行号指令

语法:

#line lineno    (1) 
#line lineno "filename" (2) 

改变指令之后的LINE变量和FILE变量。

#include <cassert>
#define FNAME "test.cc"
int main()
{
#line 777 FNAME
        assert(2+2 == 5);
}
//output: test: test.cc:777: int main(): Assertion `2+2 == 5' failed.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值