美文网首页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语言:调试宏

    使用教材 《“笨办法” 学C语言(Learn C The Hard Way)》https://www.jiansh...

  • C语言练习题: 函数部分

    C语言练习题:函数部分(9题) 上一篇: C语言练习题:循环部分 下一篇: C语言练习题:数组部分 斐波那契,函数...

  • C语言练习题:循环部分

    C语言练习题:循环部分(20题) 上一篇: C语言练习题:if语句部分 下一篇: C语言练习题:函数部分 求一正整...

  • iOS [Objective-C] 中的Debug表达式

    表1:预定义的宏和C/C++/Objective-C调试函数 表2:OBjective-C中的调试函数

  • C语言 巧用宏定义来调试

    上面代码很简单,只要有学过C语言大家都懂,下面分析下这两行宏定义 #define DbgPrintf /\/Dbg...

  • C/C++ 调试技巧

    C/C++ 调试技巧 from my csdn blog 调试宏 assert() 参数为一个断言为真的表达式,如...

  • 日志调试宏(C )

    C语音中常用的宏: 使用举例: #define LOG(fmt, ...) printf("[%s,%s:%4d]...

  • C语言--调试

    首先来了解一下文件默认的输出信息的函数: 其中cleam_finame((_FILE_)定义为 作用是只输出文件名...

  • 精解C语言预处理命令(三)之“宏”的用法二

    关于C语言带参数的宏定义中的参数 C语言允许宏带有参数。在宏定义中的参数称为“形式参数”,在宏调用中的参数称为“实...

  • C语言习题讲解

    1.模块化 例一:100以内素数---存储数组1.判断素数isprim()2.2-100存入新的数组 2.数据类型...

网友评论

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

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