C Newbie Helper
注意事项 | FYA
- 如果您将日志输出到文件中,请注意本工具只会不断追加,不会主动清空日志文件。所以请您做好日志的手动清空或备份管理工作。
    
- 换句话说,如果你不希望几次运行的日志全都在同一个文件里无法区分,那么请在每次运行完以后删除日志文件或者重命名它。
 
 - 该工具中的宏函数都需要在函数内使用,也就是说你不能把它写在函数外,当然我相信几乎没有人会这么做。
 
使用之前的设置 | Config
说明:
- 
    
该项内容需要您手动修改源代码中的对应部分,请放心,它被放在来代码的头部,很好找。
 - 如果您希望日志打印在屏幕上但没有颜色高亮,设置为
2; - 如果您希望日志打印在屏幕上并且有颜色(CMD无法使用),设置为
1; - 如果希望日志打印在文件中,设置为
0: 
设置为1时效果最佳,但对于不熟悉命令行的一般同学我们推荐使用2,在有特殊需求时可以使用0
// MODE 0 : Logs will be write to 'CNH_log.txt' file.
// MODE 1 : Logs will be print to console (colorful for normal terminal).
// MODE 2 : Logs will be print to console (colorless but fine for CMD).
#define CNH_MODE 2
此外,CNH 默认输出到 stderr 中,如果希望它在和 printf 一起使用且顺序不变时,请改为 stdout 。
使用 | Usage
导入 | Import
- 对于尚在学习单文件编程的同学,我们建议您直接复制
CNewbieHelper.h中的所有内容至你的代码的最前。 - 如果您觉得这太过累赘,那么请在本地将
CNewbieHelper.h文件与您正在编写的.c文件放在同一目录,并在代码的开头写上#include "CNewbieHelper.h",但请注意,此时您无法直接将代码内容提交至在线评测工具(比如PTA)。解决方法请参考上一条。 - 对于已经知道如何进行多模块编程的同学,我们建议您直接
#include "CNewbieHelper.h" 
显示 | Show
说明:在保留调试代码的情况下,控制是否显示日志内容。
- 默认情况下,该工具都会默认输出所有日志内容;
 - 您也可以通过调用
SET_CNH_SHOW(0);来关闭显示; - 在关闭之后您也可以通过
SET_CNH_SHOW(1);来启用显示; 
// Run 'demo1.c' to see more!
int main(){
    SET_CNH_SHOW(1);
    LOG("(QWQ) I can be seen!");
	SET_CNH_SHOW(0);
    LOG("(QAQ) I can't be seen!");
}
简化 | Simplify
说明:如果您认为正常的输出过于花哨,CNH提供了两套方案来调整输出的格式。
使用如下方法可以全局性地更改输出格式:
- 使用
SET_CNH_BRIEF_MODE(1);来启用简化模式; - 使用
SET_CNH_BRIEF_MODE(0);来关闭简化模式; 
使用BRIEF();和NORMAL();可以局部性地修改输出格式:
// Run 'demo2.c' to see more!
int main(){
    SET_CNH_BRIEF_MODE(0);
    LOG("Normal mode here!");
	BRIEF(
		LOG("Brief mode here!");
        LOG("Multiline is ok!");
	);
    LOG("Normal mode here!");
    SET_CNH_BRIEF_MODE(1);
	LOG("Brief mode here!");
    NORMAL(
		LOG("Normal mode here!");
        LOG("Multiline is ok!");
    );
	LOG("Brief mode here!");
}
预览:
正常输出模式:

简化输出模式:

一般日志 | Log
使用LOG(...)来输出一般日志。
LOG()的使用方法和printf()基本一致,只需要把printf()语句中的函数名换成LOG即可。
举个例子:
如果您想在某一处输出一条日志语句:
    char myCharArr[] = "It's OK!";
    LOG("This is a log message. %s", myCharArr);
监控变量 | Variable Monitor
使用SHOW_VAR(CNH_TYPE, CNH_VAR)来监控变量。
- 其中
CNH_TYPE指对应变量在printf()的 format 中所使用的占位符,例如int对应的CNH_TYPE为"%d",double对应的CNH_TYPE为"%lf";- 当然,由于该宏函数的底层使用的是
printf(),所以实际上相关的扩展语法都是支持的。比如"%.2lf" 
 - 当然,由于该宏函数的底层使用的是
 CNH_VAR指对应变量;
举个例子:
如果您想在某一处监控int类型变量x,则在该位置写上:
    SHOW_VAR("%d", x);
监控数组 | Array Monitor
一维数组
使用SHOW_ARR(CNH_TYPE, CNH_ARR_NAME, CNH_ARR_BEGIN, CNH_ARR_END)来监控数组。
- 其中
CNH_TYPE指对应变量在printf()的 format 中所使用的占位符,同上; CNH_ARR_NAME指数组名,例如int a[10];中的a;CNH_ARR_BEGIN和CNH_ARR_END分别为需要监控的数组的始末下表,且左闭右开;- 具体来说,比如为想监控
a[0]a[1]a[2]a[3]…a[9],那么对应的CNH_ARR_BEGIN为0,CNH_ARR_END为10; - 换句话来说,这个宏函数只能用来监控一维数组的连续段;
 
- 具体来说,比如为想监控
 
举个例子:
如果您想在某一处监控int类型数组a[],范围是a[0]到a[10],则在该位置写上:
    SHOW_ARR("%d", a, 0, 10);
二维数组
使用SHOW_2_ARR(CNH_TYPE, CNH_ARR_NAME, CNH_ARR_ROW_NUM, CNH_ARR_COL_NUM)来监控数组。
- 其中
CNH_TYPE指对应变量在printf()的 format 中所使用的占位符,同上; CNH_ARR_NAME指数组名,例如int a[10][10];中的a;CNH_ARR_ROW_NUM和CNH_ARR_COL_NUM分别为需要监控的二维数组的行数和列数;- 具体来说,比如为想监控这样一个二维数组:
 
int a[3][4] = {...};
- 那么对应的
CNH_ARR_ROW_NUM为3,CNH_ARR_COL_NUM为4; - 换句话来说,这个宏函数只能用来监控二维数组从
( 0 , 0 )到( CNH_ARR_ROW_NUM-1 , CNH_ARR_COL_NUM-1 )的矩阵。 
举个例子:
如果您想在某一处监控上面那个二维数组a[][],则在该位置写上:
    SHOW_2_ARR("%d", a, 3, 4);
任意维数组
使用SHOW_N_ARR(CNH_TYPE, CNH_ARR_NAME, CNH_ELEMENT_SIZE, CNH_SIZE)来监控任意维数组。
- 其中
CNH_TYPE指对应变量在printf()的 format 中所使用的占位符,同上; CNH_ARR_NAME指数组名,例如int a[10][10];中的a;CNH_ELEMENT_SIZE和CNH_SIZE分别为需要监控的数组的每一个元素的大小和整个数组的大小,一般推荐直接写成sizeof(<EleType>)和sizeof(<ArrName>);- 具体来说,比如有一个三维
double类数组a[11][45][14],则: CNH_ELEMENT_SIZE为sizeof(double);CNH_SIZE为sizeof(a); 举个例子:
- 具体来说,比如有一个三维
 
如果您想在某一处监控上面那个三维数组a[][],则在该位置写上:
    SHOW_2_ARR("%lf", a, sizeof(double), sizeof(a));