zoukankan      html  css  js  c++  java
  • C/C++预定义宏

    编译器识别预定义的 ANSI/ISO C99 C 预处理宏,Microsoft C++ 实现将提供更多宏。些预处理器宏不带参数,并且不能重新定义。

    ANSI 兼容的预定义宏

    __FILE__,__LINE__,__func__,__DATE__,__TIME__,__TIMESTAMP__
     
    1 . __FILE__,__LINE__,__FUNCTION__或者__func__

    __FILE__:当前程序行所在源文件名称,标准C支持,该宏当做字符串对待;
    __LINE__:当前程序行所在源文件内的行号,标准C支持,该宏当做整形对待;
    __FUNCTION__或者__func__:当前程序行所属的函数名称,C99支持(如:VC++6.0不支持),该宏当做字符串对待;

    结合打印日志功能,这些信息将有助于调试。简单的使用方法:

    //将该程序保存为test.cpp
    #include <iostream>
    using namespace std;
    int main(int argc, char *argv[])
    {
        printf("FILE:%s|LINE:%d|FUNCTION:%s|%s
    ", __FILE__, __LINE__, __FUNCTION__, __func__);
        return 0;
    }

    执行上述程序将打印:FILE:test.cpp|LINE:8|FUNCTION:main|main


    特别说明,据参考资料中关于__func__的信息称,__func__不是一个宏,它是编译隐式声明的常量字符数组:static const char __func__[] = "function-name"。

    2 . __DATE__,__TIME__,__TIMESTAMP__

    __DATE__:当前文件的编译日期,格式是Mmm:dd:yyyy。该宏当做字符串对待。
    __TIME__:当前文件的编译时间,格式是hh:mm:ss。该宏当做字符串对待。

    __TIMESTAMP__:当前源文件的最近一次的修改日期和时间,格式是Ddd Mmm Date hh:mm:ss yyyy 。该宏当做字符串对待。

    编译源文件时,假如该宏,可以让程序打印出编译时间,达到区分不同版本的目的。简单使用方法如下:

    #include <iostream>
    using namespace std;
    int main(int argc, char *argv[])
    {
        printf("DATE:%s|TIME:%s|TIMESTAMP:%s
    ", __DATE__, __TIME__,__TIMESTAMP__);
        getchar();
        return 0;
    }

    执行上述程序将打印:DATE:Oct 20 2010|TIME:23:33:24。

    不重新编译程序的情况下,每次执行该程序打印的都将是是这个时间,而不是系统的当前时间。

    3 -- #line

    #line用于重置由__LINE__和__FILE__宏指定的行号和文件名。比如说我们有这么一个测试程序:

    //将该程序保存为test.cpp
    #include <iostream>
    using namespace std;
    int main(int argc, char *argv[])
    {
    #line 100 "baidu.cpp"
        printf("FILE:%s|LINE:%d
    ", __FILE__, __LINE__);
        return 0;
    }

    注释掉第8行代码,程序打印:FILE:test.cpp|LINE:9
    不注释第8行代码,程序打印:FILE:baidu.cpp|LINE:100

    可见:#line指定下行代码的起始行号和源文件名称,作用域到文件末尾或者再次#line的使用处。

    4 -- __GUNC__

    __GUNC__,是GCC编译器的预定义,表明当前GNUC编译的版本。__GNUC__ 的值表示gcc的版本,需要针对gcc特定版本编写代码时,可以使用该宏进行条件编译。

    6 -- 宏定义的"#"和"##"使用方法

    "#":替换宏参数时,将其后面的宏参数转换成带引号的字符串,例如:

    #define STR(s) #s
    int main()
    {
        std::string str = STR(abcdefg);
        return 0;
    }

    C编译器在预处理代码时,第5行实际翻译成:std::string str = "abcdefg";

    "##":将该符号前后的两个宏参数连接在一起,比如:

    #define PRINT(PRINT_FUNNAME, VAR) print_##PRINT_FUNNAME(VAR)
    int main()
    {
        PRINT(common, 5);
        return 0;
    }

    C编译器在预处理代码时,第5行实际翻译成:print_common(5);

    我们实际看下综合运用的例子:

    //#include <iostream>
    #define PRINT(fun, name, var) print_##fun(#name, var)
    void print_common(const std::string & name, int var)
    {
        std::cout << name << ":" << var << std::endl;
    }
    void print_tofile(const std::string & name, int var)
    {
        char sz_temp[1024];
        memset(sz_temp, 0, sizeof(sz_temp));
        snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);
        FILE * fp = fopen("./log.log", "w");
        fwrite(sz_temp, 1, strlen(sz_temp), fp);
        fclose(fp);
    }
    int main()
    {
        PRINT(common, age, 5);
        PRINT(tofile, age, 5);
        return 0;
    }

    这个代码的意思是,在主函数中以统一的调用入口"PRINT"该宏函数,通过制定不同的函数名称,将变量的名称和值打印到不同的地方,比如屏幕或者文件中。
    我们使用g++ -E marco.cpp预处理命令查看下预处理后的源文件:

    # 1 "marco.cpp"
    # 1 "<built-in>"
    # 1 "<command line>"
    # 1 "marco.cpp"
    void print_common(const std::string & name, int var)
    {
        std::cout << name << ":" << var << std::endl;
    }
    void print_tofile(const std::string & name, int var)
    {
        char sz_temp[1024];
        memset(sz_temp, 0, sizeof(sz_temp));
        snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);
        FILE * fp = fopen("./log.log", "w");
        fwrite(sz_temp, 1, strlen(sz_temp), fp);
        fclose(fp);
    }
    int main()
    {
        print_common("age", 5);
        print_tofile("age", 5);
        return 0;
    }
     
  • 相关阅读:
    Django之信号
    Git协同开发操作+GitHub
    Django之auth组件
    Django之contenttyes组件
    Django之缓存
    Django之请求数据格式
    Django REST framework之渲染器组件以及阅读源码流程
    DJango REST framework之分页组件以及对源码的阅读
    Django REST framework之视图路由组件以及分层分析
    Leetcode103. Binary Tree Zigzag Level Order Traversal二叉树的锯齿形层次遍历
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/5508619.html
Copyright © 2011-2022 走看看