环境准备
- linux虚拟机
- 安装升级c/c++编译器
- gcc/g++ 选项 源代码文件1 源代码文件2 ... 源代码文件n
- -o指定输出的文件名(不能和源文件同名 默认是a.out)
- -g调试 -On链接时优化 减小体积(n=1-3) -c只编译 用于生成库
- -std=c++11 支持c++11标准
- 安装man功能
- man 级别 接口/命令
- 级别: 1系统命令 2系统接口 3库函数 4设备文件 5文件 9内核
- 安装vscode c/c++插件 简体中文插件 Remote-ssh插件
基础知识
静态库动态库
g++ -c -o libxxx.a xxx.cpp
生成了libxxx.a的静态库
g++ -o demo demo.cpp -L/path/xxx -lxxx
-L指定路径 -l指定静态库名- 用静态库和用源代码是一样的,好处是可以隐藏源代码
g++ -fPIC -shared -o libxxx.so xxx.cpp
制作动态库 调用方式同上
- 用动态库必须先把目录加到LD_LIBRARY_PATH
- 动态库是编译时不会连接到程序中,而是运行时装入,如果多个程序用到同一静态库,只在内存有一份(代码共享),避免空间浪费
**静态动态库都有 优先使用动态
makefile
每次编译都要g++ xxxx很麻烦,果然懒惰是第一生产力
# 指定编译的目标文件是生成这俩库
all:libxxx.a \
libxxx.so
# 编译libxxx.a时,如果发现后面这俩文件变化了 重新编译
libxxx.a: main.h main.cpp
g++ -c -o libxxx.a main.cpp+
# 同上
libxxx.so: main.h main.cpp
g++ -fPIC -shared -o libxxx.so main.cpp
# make clean命令
clean:
rm -f libxxx.a libxxx.so
- 增量编译,也就是说当前目录下有静态/动态了,就不编译这个了
- 用-I指定头文件包含路径
- g++前面是个tab,而不是八个空格
- main函数第三个是char* envp[] 打印出来效果如同env命令
- int setenv(const char* name, const char* value, int override) 环境变量名/值/是否替换 返回0成功-1失败(几乎不失败) 只对当前进程生效 进程终止下次就没有了,对shell无效
gdb调试
yum -y install gdb
安装- 编译时加-g 不要加-On
- gdb常用命令
- set args xx xx xx 设置参数
- break/b xx 在第某行打断点 (ctrl+g显示行号 或者vi下:set number)
- run/r 一直运行直到断点
指令 | 用处 | 其他说明 |
---|---|---|
set args xx xx | 设置参数 | |
break/b 20 | 在第20行打断点 | ctrl+g 或 :set number |
run/r | 从头一直运行直到断点 | |
next/n | 执行当前语句 | 若为函数调用不进入 |
step/s | 执行当前语句 | 进入(库函数由于无源码进不去) |
continue/c | 运行到下一个断点 | |
print/p xx | 查看变量/表达式的值 | 甚至可以p strlen(xx) p xx = 1 |
set var xx = xx | 调试时设置参数 | |
quit/q | 退出gdb |
- 出现段错误时(操作空指针) 程序会被内核强行终止,保存在core文件中(需要先ulimit -a 查看 core file size ulimit -c unlimited更改后才能看到)
gdb demo core.123
调试core文件 bt查看函数调用栈- ps -ef|grep demo 查看进程号 gdb -p demo 123 会自动停止
linux
时间 <time.h>
- time_t
typedef long time_t
- 获取1970/1/1到现在的秒数
time_t now = time(0)
time_t now; time(&now)
- tm结构体
- 从time_t转tm结构体,注意加_r 线程安全
localtime_r(&now, &tmnow)
mktime(&tm)
把结构体转time_tgettimeofday(struct timeinterval* tv, struct timezone* tz)
获取1970/1/1到现在的秒数+当前的微秒数
- sleep(秒) usleep(微秒)
目录操作<unistd.h>
- 获取当前目录
char* getcwd(char* buf, size_t size)
char* get_current_dir_name()
- 相当于pwd,目录最大长度255 getcwd需要初始化一个256长度的字符数组,get_current_dir_name需要接free
-
切换目录
int chdir(const char*path)
-
创建目录
int mkdir(const char*pathname, mode_t mode)
- mode如0755,不要省略0
- 删除目录
int rmdir(const char*path)
<dirent.h> 读取目录相当于ls -a
DIR* opendir(const char* path); //打开目录
struct dirent*readdir(DIR* dirp); //读取目录
int closedir(DIR* dirp); //关闭目录
- 其中 d_type = 8 是文件,= 4 是子目录
a
- 判断文件是否有某个权限,有返回0 没有返回-1
int access(const char* path, int mode)
-
stat结构体,有很多成员,比ls列出的还多
int stat(const char*path, struct stat*buf)
-
修改目录或文件的时间
int utime(const char* path,const struct utimbuf* time)
-
rename库函数 相当于mv
int rename(const char* old, const char* new)
-
remove库函数 相当于rm
int remove(const char* path)
Linux系统错误 <errno.h>
-
获取错误代码的详细信息
char* strerror(int errnum)
int strerror_r(int errnum, char* buf, size_t buflen)
-
控制台显示最近一次系统错误的详细信息
void perrpr(const char*s)
- 不是系统调用的函数,不会设置errorno!!!!
- 相当于出现error时,printf打印一下,但是error不会自动清零,所以一般是判断if (ret!=0) 也就是执行失败再去看错误
linux信号
可以用默认的信号操作(通常会终止进程) 也可以用signal函数自定义处理方式,但是有的信号不可被捕获、忽略 如9
sighandler_t signal(int signum, sighandler_t func)
void (*sighandler_t)(int);
- 说明信号处理函数返回值void 入参int
- func传入 SIG_IGN 表示忽略这个值的信号 SIG_DFL表示恢复默认
- alarm(5); signal(14,func); 用于定时五秒发送闹钟信号(14)然后执行func函数~~ 注意 func中需要有alarm(5) 不然就只会处理一次咯!!
进程终止
- main函数运行完return
- 函数内调用exit() 会立即退出 不会返回调用它的地方
- _exit()和Exit()
- exit() 不会调用局部变量的析构,但是会调用全局变量的析构,下面这俩直接终止不会析构
- 最后一个线程从线程主函数中返回
- pthread_exit()
- abort() 异常终止 、接收到信号、最后一个线程对取消请求作出响应
- 终止状态就是main的return值 如果exit(n)就是n 异常终止是非零
atexit() 用于注册终止函数,最多注册32个
int main(){
atexit(func1);
atexit(func2);
return 0; //正常return 或 exit 都会调用func1 func2
}
标签:const,reactor,int,libxxx,c++,char,xx,服务器,main
From: https://www.cnblogs.com/xsl-blogs/p/18061012