函数模块
命令行解析
作为程序开始的第一步,当然长短命令都要处理,直接开整!
#include <getopt.h>
#define XXX_ARG 1000 // 用于仅长选项,后面数字可随便定义
/**
* 命令行解析类
* 一般仅用于解析、检验合理性
* 图方便可以把参数直接存在这里,函数体较大的话就存在另一个Param类里
*/
class CommandParse
{
public:
CommandParse() {}
~CommandParse() {}
void usage(int exit_code);
void doCommandParse(int argc, char **argv);
public:
int thread_ = 0;
std::string opt_;
};
/**
* 打印程序默认使用方式
*/
void CommandParse::usage(int exit_code = -1)
{
printf("\n");
printf("Command:\n");
printf(" Program [options]\n");
printf("Options:\n");
printf(" -t, --thread=N set thread number\n");
printf(" -p, --opt=STR this option can have one parameter\n");
printf(" --special special option\n");
printf(" -h, --help get this help and exit\n");
exit(exit_code);
}
/**
* 参数解析
*/
void CommandParse::doCommandParse(int argc, char **argv)
{
int opt = 0;
optind = 1;
while(true)
{
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'}, // -h,--help 无参选项
{"thread", required_argument, 0, 't'}, // -t,--thread 单参选项
{"opt", optional_argument, 0, 'p'}, // -p,--opt 单参选项,可有1个或0个,参数必须紧跟在选项后
{"special", no_argument, 0, XXX_ARG}, // --special 仅长选项,无参
{0, 0, 0, 0}
};
int option_idx = 0;
opt = getopt_long(argc, argv, "?ht:p::", long_options, &option_idx);
if (opt == -1)
break;
switch(opt)
{
case '?':
case 'h':
usage();
break;
case 't':
thread_ = atoi(optarg);
break;
case 'p':
if (optarg == nullptr){
// no parameter
} else {
opt_ = optarg;
}
break;
case XXX_ARG:
// special option
break;
default:
usage();
break;
}
}
// 如果有剩余参数可用 argv[optind] 进行解析
}
int main(int argc, char **argv)
{
CommandParse *optptr = new CommandParse();
optptr->doCommandParse(argc, argv);
delete optptr; // REMEMBER TO DELETE!
return 0;
}
打印当前进程使用内存
#include <unistd.h>
int getCurMem()
{
char cmd[512] = {0};
int pid = getpid();
sprintf(cmd, "cat /proc/%d/status | grep VmRSS 2>&1\n", pid); // 子进程要执行的命令
FILE *fp = popen(cmd, "r"); // 启动子进程
if (fp != NULL)
{
char buf[512] = {0};
int readlen = fread(buf, sizeof(char), sizeof(buf), fp); // 获取命令结果
if (readlen > 0)
{
fprintf(stdout, "%s", buf);
}
pclose(fp);
}
return 0;
}
获取大文件大小
uint64_t getBigFileSize(const char *filename)
{
uint64_t size;
FILE *fp = fopen(filename, "r");
if (fp == nullptr)
{
fprintf(stderr, "open %s failed", filename);
exit(-1);
}
if (0 != fseeko64(fp, 0, SEEK_END))
{
fprintf(stderr, "move cursor failed");
exit(-1);
}
size = ftello64(fp);
fclose(fp);
return size;
}
gdb调试
用gdb调试程序是c/c++软件工程师必备的一个技能,那么话不多说直接开整!
注:程序想要调试一般需要有堆栈信息哦,编译时加上-g
选项就可以了,另外测试自己的代码时最好编译优化选项选用-O0
,这样不会被编译器优化掉太多信息。
启动gdb
gdb可以调试程序、运行中的程序,或者查看程序崩溃后产生的core文件,命令都差不多
// 调试程序
gdb <program>
// 查看core文件
gdb <program> <core file>
// 调试运行中的程序
gdb attach <pid>
常用命令
set print pretty on 设置打印结构体之类的漂亮点
短写 完整命令 说明
r run 运行程序
r <parameters>
q quit 退出gdb
l list 查看当前运行位置附近的代码
c continue 继续运行程序
n next 单步执行(不进入调用函数体)
s step 单步执行(进入调用函数体)
until N 执行到第N行
bt backtrace 查看调用栈信息
f N frame N 切换指定栈
// 断点
b breakpoint 普通断点
w watch 观察断点(关注变量变化)
catch 捕捉断点(关注抛出异常处,我没用过)
b xxx.cpp:N 在xxx.cpp的第N行位置打断点
b XXX::func 在XXX类的函数func入口处打断点
delete N 清除N号断点(不加编号则表示删除所有断点)
clear xxx.cpp:N 清除位于xxx.cpp的第N行的所有断点
enable/disable N 打开/关闭第N号断点
ignore N M 忽略N号断点M次
// 查看或修改变量或表达式的值
p print 查看一次变量或表达式的值
display 设定一次后,每次程序暂停时都自动打印出来该变量或表达式的值
p var_name 查看变量
p 0x0000 查看地址
// 查看相关信息
i info 查看信息
info break 查看断点信息(后面可加编号查看指定断点信息)
info threads 查看所有线程信息
threads N 切换到第N号线程
info register 查看寄存器信息
TUI窗口模式
gdb调试由于看代码很不方便,最好还是再打开一个代码编辑器和gdb结合使用,不过这样需要来回切换。现在有了更好的解决方案GDB TUI Mode!
注1:其实也不算很好用,更好的替代可以看CGDB,跟GDB TUI差不多但有些更好的功能,如代码高亮、可视化断点等。
这里就简单介绍一下吧。
- 进入/退出TUI:Ctrl + x, Ctrl + a、Ctrl + x, a、Ctrl + x, A等都可以
- 四个窗口:cmd(command)命令窗口、src(source)源码窗口、asm(assembly)汇编代码窗口、reg(register)寄存器窗口。(三个字母对应每个窗口的名字)
- 默认显示命令窗口和源码窗口。
- 一般情况下PageUp、PageDown、方向键等是对active的窗口进行操作,可通过
focus [next | prev | <window name>]
切换active窗口。 - 在cmd窗口下所有命令与上述gdb模式保持一致。
- 切换窗口
- Ctrl + 1仅显示一个窗口,重复按下则按顺序切换显示窗口
- Ctrl + 2同时显示两个窗口,重复按下则按顺序切换显示窗口
- 使用
layout [next | prev | <window name>]
切换指定窗口
注2:Ctrl + L刷新窗口
标签:opt,fp,窗口,int,知识,C++,gdb,断点 From: https://blog.csdn.net/PYPYPYJ/article/details/145199081