美文网首页c语言
[习题19]C语言:调试宏

[习题19]C语言:调试宏

作者: AkuRinbu | 来源:发表于2018-10-31 00:01 被阅读19次

    使用教材

    《“笨办法” 学C语言(Learn C The Hard Way)》
    https://www.jianshu.com/p/b0631208a794

    • 完整源码 : learn-c-the-hard-way-lectures/ex19/

    https://github.com/zedshaw/learn-c-the-hard-way-lectures/tree/master/ex19

    目录

    • 附加任务一
    • 附加任务二
    • 源码及输出展示

    附加任务 一

    1、使调试信息不输出

    做法一,在ex19.c文件顶部加入#define NDEBUG

    注释掉就会输出调试信息,解除注释就可以屏蔽调试信息
    • dbg.h文件,这里指出,如果有定义NDEBUG ( 就是这句 #ifdef NDEBUG ),随之一个debug(M,...) 替换内容为(实现什么调试信息都不输出),否则才是按照else分支里的输出,文件名:行号以及其他信息
    #ifdef NDEBUG
    #define debug(M, ...)
    #else
    #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\
        __FILE__, __LINE__, ##__VA_ARGS__)
    #endif
    
    • 需要指出,这个宏函数,debug完全是我们自己命名的,自己定义的,也就是说,我让它成为一个输出调试信息的函数,我叫它是调试函数,我认为什么是调试信息,那就输出什么,管它是源码文件名还是行数还是时间还是今天天气真不错都可以,同时,它可以叫debug,就可以叫helloworld,叫什么都是我们自己决定的, 只不过我们让它充当所谓的调试信息输出函数

    • 决定我们想要的信息输出与否的关键是这个,#ifdef #else的条件语句

    #ifdef A
    #define B C
    #else
    #define D E
    

    做法二,CPPFLAGS=-DNDEBUG

    • #ifdef NDEBUG,这里自己取名的NDEBUG前面加个D
    $ make CPPFLAGS=-DNDEBUG ex19
    clang -Wall -g -DNDEBUG   ex19.c   -o ex19
    

    附加任务 二

    2、修改日志记录机制,让它报告函数名称以及file:line格式的行号;

    • 做法,修改dbg.h文件中的 log_info(M, ...)加入__FUNCTION__以及%s
    #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n",\
        __FILE__ ,__FUNCTION__,__LINE__, ##__VA_ARGS__)
    
    • __FILE__ __LINE__

    3.7.1 Standard Predefined Macros
    https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

    fprintf

    https://en.cppreference.com/w/c/io/fprintf

    int fprintf( FILE *stream, const char *format, ... );
    int fprintf( FILE *restrict stream, const char *restrict format, ... );

    源码及输出展示

    • 命令行输出
    • 来自 ex19.c
    • 来自 dbg.h

    check(A, M, ...)

    • 宏替换不是简单的文本替换,checkgoto errormain函数里面最后那里的error,有一点汇编里面的标号的味道
    // ex19.c
    int main(int argc, char *argv[])
    {
        check(argc==2, "Need an argument.");
    
            return 0;
            
        error:
            return 1;
    }
    
    // dbg.h
    #define check(A, M, ...) if(!A) {\
        log_err(M, ##__VA_ARGS__); errno=0; goto error; }
    

    debug(M, ...)

    DEBUG ex19.c:8: I have Brown Hair.
    DEBUG ex19.c:11: I am 37 years old.
    
    void test_debug()
    {
        // notice you don't need the \n
        debug("I have Brown Hair.");
    
        // passing in arguments like printf
        debug("I am %d years old.", 37);
    }
    
    #ifdef NDEBUG
    #define debug(M, ...)
    #else
    #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\
        __FILE__, __LINE__, ##__VA_ARGS__)
    #endif
    

    log_err

    [ERROR] (ex19.c:16: errno: None)I believe everthing is broken.
    [ERROR] (ex19.c:17: errno: None)There are 0 problem in space
    
    void test_log_err()
    {
        log_err("I believe everthing is broken.");
        log_err("There are %d problem in %s",0, "space");
    }
    
    #define log_err(M, ...) fprintf(stderr,\
        "[ERROR] (%s:%d: errno: %s)" M "\n", __FILE__, __LINE__,\
        clean_errno(), ##__VA_ARGS__)
    

    log_warn(M, ...)

    [WARN] (ex19.c:22: errno: None) You can safely ignore this.
    [WARN] (ex19.c:23: errno: None) Maybe consider looking at:/etc/passwd.
    
    void test_log_warn()
    {
        log_warn("You can safely ignore this.");
        log_warn("Maybe consider looking at:%s.", "/etc/passwd");
    }
    
    #define log_warn(M, ...) fprintf(stderr,\
        "[WARN] (%s:%d: errno: %s) " M "\n",\
        __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
    

    log_info(M, ...)

    [INFO] (ex19.c:28) Well I did somehting mundane.
    [INFO] (ex19.c:29) It happened 1.300000 times today
    
    void test_log_info()
    {
        log_info("Well I did somehting mundane.");
        log_info("It happened %f times today", 1.3f);
    }
    
    #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\
        __FILE__, __LINE__, ##__VA_ARGS__)
    

    test_check

    [ERROR] (ex19.c:41: errno: Bad address)Failed to open (null).
    
    int test_check(char *file_name)
    {
        FILE *input = NULL;
        char *block = NULL;
    
        block = malloc(100);
        check_mem(block);
    
        input = fopen(file_name, "r");
        check(input, "Failed to open %s.", file_name);
    
        free(block);
        fclose(input);
        return 0;
    
    error:
        if (block) free(block);
        if (input) fclose(input);
        return -1;
    
    }
    
    #define check_mem(A) check((A) , "Out of memeory.")
    
    check(test_check(argv[1]) == -1, "failed with argv");
    

    sentinel(M, ...)

    [INFO] (ex19.c:60) It worked.
    [ERROR] (ex19.c:63: errno: None)I shouldn't run.
    
    #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); \
        errno=0; goto error; }
    
    int test_sentinel(int code)
    {
        char *temp = malloc(100);
        check_mem(temp);
    
        switch (code) {
            case 1:
                log_info("It worked.");
                break;
            default:
                sentinel("I shouldn't run.");
        }
    
        free(temp);
        return 0;
    
    error:
        if (temp)
            free(temp);
        return -1;
    }
    
    check(test_sentinel(1) == 0 , "test_sentinel failed");
    check(test_sentinel(100) == -1, "test_sentinel failed");
    

    test_check_mem

    [ERROR] (ex19.c:78: errno: None)Out of memeory.
    
    int test_check_mem()
    {
        char *test = NULL;
        check_mem(test);
    
        free(test);
        return 1;
    
    error:
        return -1;
    }
    
    check(test_check_mem() == -1, "test_check_mem failed");
    

    check_debug(A, M, ...)

    DEBUG ex19.c:90: Oops, I was 0.
    
    #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS___);\
        errno=0; goto error; }
    
    check(test_check_debug() == -1, "test_check_debug failed");
    

    相关文章

      网友评论

        本文标题:[习题19]C语言:调试宏

        本文链接:https://www.haomeiwen.com/subject/cidvzftx.html