调试打印文件名等信息
#define _DEBUG_TRACE_CMH_ 2
#if 0 != _DEBUG_TRACE_CMH_
#include <cstdio>
#endif
#if 1==_DEBUG_TRACE_CMH_ //普通打印
#define TRACE_CMH printf
#elif 2==_DEBUG_TRACE_CMH_ //打印文件名、行号
#define TRACE_CMH(fmt,...) \
printf("%s(%d): "##fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#elif 3==_DEBUG_TRACE_CMH_ //打印文件名、行号、函数名
#define TRACE_CMH(fmt,...) \
printf("%s(%d)-<%s>: "##fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
#define TRACE_CMH
#endif //_TRACE_CMH_DEBUG_
这段代码中用到了这几个宏:
1) __VA_ARGS__ 是一个可变参数的宏,这个可宏是新的C99规范中新增的,目前似乎gcc和VC6.0之后的都支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用。
2) __FILE__ 宏在预编译时会替换成当前的源文件名
3) __LINE__ 宏在预编译时会替换成当前的行号
4) __FUNCTION__ 宏在预编译时会替换成当前的函数名称
函数Trace:
#define FUNC_ENTRY \
{\
printf("FUNC_ENTRY: %s L#%d \n", __func__, __LINE__); \
}
#define FUNC_EXIT \
{\
printf("FUNC_EXIT: %s L#%d \n", __func__, __LINE__); \
}
#define FUNC_EXIT_RC(x) \
{\
printf("FUNC_EXIT: %s L#%d Return Code : %d \n", __func__, __LINE__, x); \
return x; \
}
只显示文件名,不显示路径
#include <string.h> //strrchr()函数所需头文件
windows:
#define filename(x) strrchr(x,'\\')?strrchr(x,'\\')+1:x
linux:
#define filename(x) strrchr(x,'/')?strrchr(x,'/')+1:x
Marvell SDK
#ifdef LOG_DEBUG
#define filename(x) strrchr(x,'/')?strrchr(x,'/')+1:x
#define my_d(_fmt_, ...) \
wmprintf(_fmt_ "\r\n", ##__VA_ARGS__)
#define my_entry_d(_fmt_, ...) \
wmprintf("[%s(%d) - %s] " _fmt_ "\r\n", filename(__FILE__), __LINE__, __func__, ##__VA_ARGS__)
#else
#define my_d(...)
#define my_entry_d(...)
#endif
我习惯的写法
#ifdef CONFIG_MY_DEBUG
#define LOG(LogTypeString,format,...) printf("%s[" __FUNCTION__ "] "format, LogTypeString, __VA_ARGS__)
#define CONERR(format,...) LOG("Error:",format,__VA_ARGS__)
#define CONMSG(format,...) LOG("",format,__VA_ARGS__)
#define CONWRN(format,...) LOG("Warn:",format,__VA_ARGS__)
#define CONDBG(format,...) LOG("",format,__VA_ARGS__)
#else
#define LOG(LogTypeString,format,...)
#define CONERR(format,...)
#define CONMSG(format,...)
#define CONWRN(format,...)
#define CONDBG(format,...)
#endif
配置echo格式
echo显示带颜色,需要使用参数-e
格式如下:
echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"
例如:
echo -e "\033[41;37m TonyZhang \033[0m"
其中41的位置代表底色, 37的位置是代表字的颜色
注:
1、字背景颜色和文字颜色之间是英文的“""”
2、文字颜色后面有个m
3、字符串前后可以没有空格,如果有的话,输出也是同样有空格
下面看几个例子:
echo -e "\033[30m 黑色字 \033[0m"
echo -e "\033[31m 红色字 \033[0m"
echo -e "\033[32m 绿色字 \033[0m"
echo -e "\033[33m 黄色字 \033[0m"
echo -e "\033[34m 蓝色字 \033[0m"
echo -e "\033[35m 紫色字 \033[0m"
echo -e "\033[36m 天蓝字 \033[0m"
echo -e "\033[37m 白色字 \033[0m"
echo -e "\033[40;37m 黑底白字 \033[0m"
echo -e "\033[41;37m 红底白字 \033[0m"
echo -e "\033[42;37m 绿底白字 \033[0m"
echo -e "\033[43;37m 黄底白字 \033[0m"
echo -e "\033[44;37m 蓝底白字 \033[0m"
echo -e "\033[45;37m 紫底白字 \033[0m"
echo -e "\033[46;37m 天蓝底白字 \033[0m"
echo -e "\033[47;30m 白底黑字 \033[0m"
控制选项说明 :
\33[0m 关闭所有属性
\33[1m 设置高亮度
\33[4m 下划线
\33[5m 闪烁
\33[7m 反显
\33[8m 消隐
\33[30m -- \33[37m 设置前景色
\33[40m -- \33[47m 设置背景色
\33[nA 光标上移n行
\33[nB 光标下移n行
\33[nC 光标右移n行
\33[nD 光标左移n行
\33[y;xH设置光标位置
\33[2J 清屏
\33[K 清除从光标到行尾的内容
\33[s 保存光标位置
\33[u 恢复光标位置
\33[?25l 隐藏光标
\33[?25h 显示光标
字符串转换操作
/*将字符串s转换成相应的十进制整数*/ 例如 "10" -> 10
int atoi(char s[])
{
int i;
int n = 0;
for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i) {
n = 10 * n + (s[i] - '0');
}
return n;
}
/*将大写字母转换成小写字母*/
int tolower(int c)
{
if (c >= 'A' && c <= 'Z') {
return c + 'a' - 'A';
}
else{
return c;
}
}
//将十六进制的字符串转换成整数
int htoi(char s[])
{
int i;
int n = 0;
if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) {
i = 2;
}
else {
i = 0;
}
for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i) {
if (tolower(s[i]) > '9') {
n = 16 * n + (10 + tolower(s[i]) - 'a');
}
else {
n = 16 * n + (tolower(s[i]) - '0');
}
}
return n;
}
// 十六进制数组 -> 字符串
int hex2str(uint8_t *src, char *dst, int len)
{
int i;
uint8_t hb;
uint8_t lb;
for(i = 0 ; i < len ; i++){
hb = (src[i] & 0xf0) >> 4;
if((hb >= 0)&&(hb <= 9))
hb += 0x30;
else if((hb >= 10)&&(hb <= 15))
hb = hb - 10 + 'A';
else
return 1;
lb = src[i] & 0x0f;
if((lb >= 0)&&(lb <= 9))
lb += 0x30;
else if((lb >= 10)&&(lb <= 15))
lb = lb - 10 + 'A';
else
return 1;
dst[i*2] = hb;
dst[i*2+1] = lb;
}
return 0;
}
// 字符串 -> 16进制
void strToHex(char *pbDest, char *pbSrc, int nLen)
{
char h1,h2;
char s1,s2;
int i;
for (i=0; i<nLen; i++){
h1 = pbSrc[2*i];
h2 = pbSrc[2*i+1];
s1 = toupper(h1) - 0x30;
if (s1 > 9)
s1 -= 7;
s2 = toupper(h2) - 0x30;
if (s2 > 9)
s2 -= 7;
pbDest[i] = s1*16 + s2;
}
}
输出限制范围内的随机数
static int get_rand(int limit)
{
int val;
while (1) {
val = rand() % limit;
if (val)
break;
}
return val;
}
另外,关于time_t和tm讲解,有一篇不错的参考文章:
http://blog.csdn.net/luoweifu/article/details/20288549
GDB
参考文章:
GDB十分钟教程: http://blog.csdn.net/liigo/article/details/582231/
命令 | 解释 | 示例 |
file <文件名> | 加载被调试的可执行程序文件。 因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。 | (gdb) file gdb-sample |
r | Run的简写,运行被调试的程序。 如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。 | (gdb) r |
c | Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 | (gdb) c |
b <行号> b <函数名称> b *<函数名称> b *<代码地址> d [编号] | b: Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。 其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。 d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。 | (gdb) b 8 (gdb) b main (gdb) b *main (gdb) b *0x804835c (gdb) d |
s, n | s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数; n: 执行一行源程序代码,此行代码中的函数调用也一并执行。 s 相当于其它调试器中的“Step Into (单步跟踪进入)”; 这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。 | (gdb) s (gdb) n |
si, ni | si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。 | (gdb) si (gdb) ni |
p <变量名称> | Print的简写,显示指定变量(临时变量或全局变量)的值。 | (gdb) p i (gdb) p nGlobalVar |
display ... undisplay <编号> | display,设置程序中断后欲显示的数据及其格式。 例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令 “display /i $pc” 其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。 undispaly,取消先前的display设置,编号从1开始递增。 | (gdb) display /i $pc (gdb) undisplay 1 |
i | Info的简写,用于显示各类信息,详情请查阅“help i”。 | (gdb) i r |
q | Quit的简写,退出GDB调试环境。 | (gdb) q |
help [命令名称] | GDB帮助命令,提供对GDB名种命令的解释说明。 如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。 | (gdb) help display |
设置某个文件某一行断点:
(gdb) break [<file-name>:]<func-name> (gdb) break [<file-name>:]<line-num> |