C++ 预编译命令

C++ 预编译命令

C++预处理指令

#include

#define

#undef

#pragma

#import

#error

#line

#ifdef

#ifndef

#if

#else

#elif

#endif

 

宏以#起始 不以;结束

 

一.        #include 文件包含

预编译期发现#include后,将会寻找HeaderName并把其包含到当前文件中

EG:#include <HeaderName>

常见形式:

#include <iostream.h>          //

#include <iostream>            //

#include "iostream"            //

#include "TestHeader.h"        //

#include "../TestHeader.h"     //

 

1.      #include <iostream.h>和#include <iostream>区别

#include <iostream.h>是老规范,现已经抛弃

#include <iostream>是新规范,使用名称空间避免名称冲突。即将所有的定义放在了一个名称空间std中

 

2.      #include <iostream>和#include "iostream"区别

#include <iostream>直接在系统的路径下查找此头文件。多是系统的头文件

#include "iostream"首先在当前目录查找,如果没有找到再到系统目录查找

 

3.      头文件的多次包含问题

编译器对每个文件只编译一次生成一份机器代码.obj,如果在多个地方包含了同一个头文件,则会出现多次包含的错误,即试图让编译器将此文件编译多次生成多份机器代码。

预编译保护解决此问题。

 

二.        #define  #undef 宏替换

#define 宏 宏主体

宏展开:在代码中出现宏,会用宏实体代替宏

 

#define 定义常量、函数宏

#undef  结束常量、函数宏定义

 

1.    常量宏

常量宏:是最常见的一种形式。即使用一个宏代替实际的常量,如数据、字符、字符串常量等

#define CONST_VAL 2

#define MEG_EG "Test Macro!"

#define CHARACTOR_EG 'M'

 

注:

(1)    可以使用#undef结束常量宏定义,结束宏定义宏此宏不能再次使用。即时这个宏实际不存在,使用#undef结束宏定义也不是错误,相反在定义一个宏时如果不确定其是否已经定义可以先使用#undef结束其定义,然后重新定义

(2)    可以多次定义同一个宏

 

2.    函数宏

 函数宏:外形和作用都与函数类似并且有参数输入

#define MAX(x, y) ( (x>y)?x:y )

 

注:

(1)    定义函数宏是将宏体都用一个“( ) “括起来。

#define MAX(x, y) ( (x>y)?x:y )

cout << "MAX = " << MAX(1,2) << endl;  //正确

 

#define MAX(x, y) (x>y)?x:y

cout << "MAX = " << MAX(1,2) << endl;  //错误。将<<和宏混淆

(2)    通常将函数宏第一为一行,但可以使用“/“定义多行宏函数

           #define MAX(x, y) ( (x>y)?/

                       x:y )

(3)    可以使用#undef结束函数宏定义

    #undef MAX(x, y)和#undef MAX都可以

(4)    宏函数产生内联代码,形式上等同与inline函数,当没有inline函数安全

(5)    宏函数不检查输入的参数(相比inline函数不安全)

(6)    宏函数没有inline函数效率高

  

3.    #运算符

#运算符可以在一个字符串中输入宏参数,使得一个字符串可以包含某个参数

EG:

#define STR_A(A) ( printf("STR_A(A) A = "#A" ") )

#define STR_B(B) ( "STR_B(B) B = "#B" " )

#define STR_C(CA, CB) ( "STR_C(CA, CB) C = "#CA"  "#CB" " )

        STR_A(1);

        cout << endl;

        cout << STR_B(2) << endl;

        cout << STR_B(B) << endl;

        cout << STR_C(CA, CB) << endl;

       

        string strB = "strB ";

        strB += " + ";

        strB += STR_B(B);

cout << "strB + Macro STR_B = " << strB << endl;

  

4.    ##运算符

  ##运算符用于创建变化的变量,即使用宏参数创建变化的变量

  

EG:

       #define VARIAVLE_NAME(N) ( n##N )

        int VARIAVLE_NAME(IntA) = 1;                // int nIntA

        int VARIAVLE_NAME(1) = 1;                   // int n1

        int VARIAVLE_NAME(2) = 1;                   // int n2

        cout << "nIntA = " << nIntA << endl;

        cout << "n" << 1 <<" = " << VARIAVLE_NAME(1) << endl;

        cout << "n" << 2 <<" = " << VARIAVLE_NAME(2) << endl;

       

        double VARIAVLE_NAME(DoubleA) = 1.1;

        cout << "nDoubleA = " << nDoubleA << endl;

      

三.        #pragma

其格式一般为: #pragma para

其中para 为参数,下面来看一些常用的参数。

(1)   #pragma once

多次包含的保护。只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。

 

等价于:(此为C/C++标准 通用性更强)

#ifndef HEADER_NAME_HPP

#define HEADER_NAME_HPP

             Your Code

#endif //END HEADER_NAME_HPP

 

(2)   #pragma warning()

#pragma warning( warning-specifier : warning-number-list

 [; warning-specifier : warning-number-list...] )

#pragma warning( push[ ,n ] )

#pragma warning( pop )

      

       EG:

       #pragma warning( disable : 4507 34; once : 4385; error : 164 )

等价于:

#pragma warning(disable:4507 34) // 不显示和号警告信息

#pragma warning(once:4385)       // 4385号警告信息仅报告一次

#pragma warning(error:164)       // 把号警告信息作为一个错误。

 

同时这个pragma warning 也支持如下格式:

#pragma warning( push [ ,n ] )

#pragma warning( pop )

这里n代表一个警告等级(1---4)。

#pragma warning( push )保存所有警告信息的现有的警告状态。

#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告

等级设定为n。

#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的

一切改动取消。例如:

#pragma warning( push )

#pragma warning( disable : 4705 )

#pragma warning( disable : 4706 )

#pragma warning( disable : 4707 )

//.......

#pragma warning( pop )

在这段代码的最后,重新保存所有的警告信息(包括,和)。

(3)   #pragma warning()

#pragma warning( warning-specifier : warning-number-list

 [; warning-specifier : warning-number-list...] )

#pragma warning( push[ ,n ] )

#pragma warning( pop )

      

       EG:

       #pragma warning( disable : 4507 34; once : 4385; error : 164 )

等价于:

#pragma warning(disable:4507 34) // 不显示和号警告信息

#pragma warning(once:4385)       // 4385号警告信息仅报告一次

#pragma warning(error:164)       // 把号警告信息作为一个错误。

 

同时这个pragma warning 也支持如下格式:

#pragma warning( push [ ,n ] )

#pragma warning( pop )

这里n代表一个警告等级(1---4)。

#pragma warning( push )保存所有警告信息的现有的警告状态。

#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告

等级设定为n。

#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的

一切改动取消。例如:

#pragma warning( push )

#pragma warning( disable : 4705 )

#pragma warning( disable : 4706 )

#pragma warning( disable : 4707 )

//.......

#pragma warning( pop )

在这段代码的最后,重新保存所有的警告信息(包括,和)。

四.        #import

常用于导入.dll

 

五.        #error

    该指令用于程序的调试, 当编译中遇到#error指令就停止编译。

     #if !defined(__cplusplus)

#error C++ compiler required.

#endif

如果没有在__cplusplus环境下,就会输出This software requires the cplusplus OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。 

六.        #line

用于重置__FILE__和__LINE__

初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,我们知道编译器对C++源码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析

    

   

   

    重置后

     

   

七.        #ifdef  #ifndef  #if  #else  #elif  #endif 条件编译

预处理器不能识别标记代码块的花括号{},对于条件编译的没有条件判断块必须使用 #endif来指定终止

1、 
    #ifdef  identifier 
              your code 
      #endif 
      如果identifier为一个定义了的符号,your code就会被编译,否则剔除 
    2、 
      #ifndef identifier 
              your code 
      #endif 
      如果identifier为一个未定义的符号,your code就会被编译,否则剔除 
    3、 
      #if  expression 
           your code 
      #endif 
      如果expression非零,your code就会被编译,否则剔除 
    4、 
      #ifdef identifier 
             your code1 
      #else 
             your code2 
      #endif 
      如果identifier为一个定义了的符号,your code1就会被编译,否则your code2     

就会被编译 
    5、 
      #if   expressin1 
            your code1 
      #elif expression2 
            your code2 
      #else 
            your code3 
      #enif   

 

八.        预定义宏

    __DATE__       进行预处理的日期

    __FILE__       当前软代码文件名的字符串文字

    __LINE__       当前源代码中的行号的整数常量

    __TIME__       源文件的编译时间

    __TIMESTAMP__  源文件的编译完整时间

  

cout << "__DATE__ = " << __DATE__ << endl;

    cout << "__FILE__ = " << __FILE__ << endl;

    cout << "__LINE__ = " << __LINE__ << endl;

    cout << "__TIME__ = " << __TIME__ << endl;

cout << "__TIMESTAMP__ = " << __TIMESTAMP__ << endl;

    

<think>好的,我现在需要帮助用户了解C++中的预编译命令,特别是#define和#ifdef等。首先,我得回忆一下这些命令的基本用法和常见场景。用户可能刚开始学习C++,所以解释需要清晰易懂,避免使用过于专业的术语。 首先,我应该从#define开始,这是最常用的宏定义指令。需要说明它用于定义宏,包括常量、函数式宏,以及注意事项,比如括号的使用和副作用的问题。然后,可能需要提到#ifndef和#ifdef,这些是条件编译指令,通常用在头文件防止重复包含,或者根据不同环境编译不同代码。 接下来是#ifdef和#ifndef的具体例子,比如检查DEBUG宏是否存在,或者平台相关的定义。这里要强调条件编译在跨平台开发中的重要性。还有#if、#elif、#else这些指令,可以处理更复杂的条件,比如根据不同的版本号启用功能。 然后,用户可能想知道其他相关指令,比如#pragma,虽然这因编译器而异,但可以简单提及。还有#undef用来取消宏定义,这个可能在大型项目中需要临时禁用某个宏时有用。 需要确保覆盖用户提到的所有预编译命令,但也要注意不要过于深入,避免让用户感到困惑。比如,可以举一些实际的代码示例,说明如何使用这些指令,但代码要简单明了。同时,要提醒用户宏可能带来的问题,比如函数式宏的参数多次求值导致的错误,以及为什么在C++中更推荐使用const和inline代替宏。 另外,用户可能没有明确问及,但条件编译的实际应用场景也很重要,比如头文件保护、调试代码的开关、不同平台的适配等。这些实际例子能帮助用户更好地理解为什么要使用这些指令。 最后,要总结一下这些指令的作用,强调它们在代码组织、调试和跨平台开发中的重要性,同时指出在现代C++中替代方案的存在,以引导用户写出更安全、易维护的代码。整个过程需要保持逻辑清晰,分点说明,让用户容易跟随。</think>在C++中,预编译命令(预处理指令)是代码编译前由预处理器处理的指令。以下是常用指令的详解: 一、#define 宏定义 1. 常量定义 ```cpp #define PI 3.14159 // 定义符号常量 #define MAX_SIZE 100 ``` 2. 函数式宏(注意潜在副作用) ```cpp #define SQUARE(x) ((x)*(x)) // 必须加括号防止优先级问题 #define MAX(a,b) ((a)>(b)?(a):(b)) ``` 3. 特殊用法 ```cpp #define DEBUG // 定义无值宏,用于条件编译 #define LOG(msg) std::cout << __FILE__ << ":" << __LINE__ << " " << msg ``` 二、条件编译指令 1. 头文件保护(必须使用) ```cpp #ifndef MYHEADER_H // 如果未定义 #define MYHEADER_H // 则定义 // 头文件内容 #endif ``` 2. 功能开关 ```cpp #ifdef DEBUG #define DEBUG_LOG(msg) std::cerr << "[DEBUG] " << msg #else #define DEBUG_LOG(msg) #endif ``` 3. 复杂条件判断 ```cpp #if __cplusplus >= 201703L // C++17特性代码 #elif defined(__GNUC__) // GCC特有代码 #endif ``` 三、其他重要指令 1. #undef 取消宏定义 ```cpp #undef PI // 后续代码不再识别PI宏 ``` 2. #pragma 编译器指令(编译器相关) ```cpp #pragma once // 非标准但广泛支持的头文件保护 #pragma pack(1) // 设置结构体对齐方式 ``` 四、注意事项 1. 现代C++替代方案: - 用constexpr替代常量宏 - 用inline函数替代函数式宏 - 用namespace避免命名冲突 2. 常见应用场景: - 跨平台编译(Windows/Linux宏区分) - 版本特性控制 - 调试日志开关 - 代码兼容性处理 示例:跨平台代码结构 ```cpp #ifdef _WIN32 #include <windows.h> #define SLEEP(ms) Sleep(ms) #else #include <unistd.h> #define SLEEP(ms) usleep(ms*1000) #endif ``` 建议:虽然预处理器功能强大,但在C++中应优先使用语言本身的特性(如const、模板、命名空间),仅在必要时使用预处理指令。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值