MERGE: fix
ADD: linux/command.md -> iperf3 FIX: program/c_cpp/universal/libs.md -> errno DEL: program/c_cpp/libs/log/ program/c_cpp/libs/dbtools.h
This commit is contained in:
parent
b462e74945
commit
d05beb0f1f
@ -124,6 +124,7 @@
|
|||||||
- [wget](#wget)
|
- [wget](#wget)
|
||||||
- [NetworkManager](#networkmanager)
|
- [NetworkManager](#networkmanager)
|
||||||
- [nmap](#nmap)
|
- [nmap](#nmap)
|
||||||
|
- [iperf3](#iperf) : 网络性能测试工具
|
||||||
|
|
||||||
- [index](#index)
|
- [index](#index)
|
||||||
|
|
||||||
@ -777,3 +778,25 @@ exit # 退出 chroot
|
|||||||
umount -R /mnt # 卸载所有分区
|
umount -R /mnt # 卸载所有分区
|
||||||
reboot
|
reboot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **iperf**
|
||||||
|
|
||||||
|
- 通用参数
|
||||||
|
- `-p` : 指定端口
|
||||||
|
- `-i` : 报告间隔时间(s)
|
||||||
|
- `-V` : 详细日志
|
||||||
|
|
||||||
|
- 客户端参数
|
||||||
|
- `-c` : 指定服务端IP
|
||||||
|
- `-u` : UDP
|
||||||
|
- `-R` : 反向传输(服务器发,客户端收)
|
||||||
|
- `-P` : 并发连接数
|
||||||
|
- `-b` : UDP目标带宽
|
||||||
|
|
||||||
|
- 服务端参数
|
||||||
|
- `-s` : 启动服务器
|
||||||
|
- `-B` : 绑定指定IP
|
||||||
|
|
||||||
|
---
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright(c) 2025 Rangersly All rights reserved.
|
|
||||||
|
|
||||||
DEBUG 工具封包
|
|
||||||
|
|
||||||
Version: v0.1-Alpha
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
/* 字符串检查宏,输出字符串的每一位数据*/
|
|
||||||
#define POINT_STR(str, len) size_t _len = (size_t)len; \
|
|
||||||
printf("%s\033[0m\n", str); \
|
|
||||||
for(int i = 0; i < _len; i++) { \
|
|
||||||
printf("%d --- %2x \n", i, (char)str[i], (unsigned char)str[i]);}
|
|
||||||
|
|
||||||
/*输出调试错误报错信息,辅助定位错误地点*/
|
|
||||||
#define PERROR(str) printf("%s:%d:%s:\n%s\n", __FILE__, __LINE__, __func__, str); exit(0)
|
|
||||||
#else
|
|
||||||
#define POINT_STR(str, len)
|
|
||||||
#define PERROR(str)
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
|||||||
#include "log.h"
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define POINT_STR(str)
|
|
||||||
#define PERROR(str)
|
|
||||||
#else
|
|
||||||
#define POINT_STR(str) for(int i = 0; i < strlen(str); i++) { \
|
|
||||||
printf("%c --- %d\n", (char)str[i], (int)str[i]);}
|
|
||||||
#define PERROR(str) printf(str);return
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int low_show_level = LOG_INFO;
|
|
||||||
static int log_number = 1;
|
|
||||||
static FILE *log_out_fp = NULL;
|
|
||||||
static char log_head_format[LOG_HEAD_MAX_FORMAT] = "[%y-%m-%d-%n]";
|
|
||||||
static char log_head[LOG_HEAD_MAX_FORMAT << 3];
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_loghead(void);
|
|
||||||
// 根据 log_head_format 生成日志头 log_head
|
|
||||||
// 有无法识别的符号返回 -1 成功返回0
|
|
||||||
|
|
||||||
static void
|
|
||||||
int_to_str(int num, char *restrict str);
|
|
||||||
// 将int 型数据转换成str
|
|
||||||
// 需要注意 str 要大于 int 的位数,否则将溢出
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
log_setoutfile(const char *restrict filename) {
|
|
||||||
if((log_out_fp = fopen(filename, "w")) == NULL)
|
|
||||||
PERROR("LOG: log_setoutfile open file fail !\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
log_setlevel(int level) {
|
|
||||||
if(level < LOG_INFO || level > LOG_FATAL) { // 检测最低日志等级
|
|
||||||
low_show_level = LOG_INFO;
|
|
||||||
PERROR("LOG: log_setlevel level is > LOG_FATAL or < LOG_INFO\n");
|
|
||||||
}
|
|
||||||
low_show_level = level;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
log_sethead(const char *restrict head) {
|
|
||||||
if(strlen(head) >= LOG_HEAD_MAX_FORMAT)
|
|
||||||
PERROR("LOG: log_sethead head so long!\n");
|
|
||||||
strncpy(log_head_format, head, LOG_HEAD_MAX_FORMAT);
|
|
||||||
if(get_loghead())
|
|
||||||
PERROR("LOG: log_sethead have fail char !\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
log_print(int level, const char *restrict message) {
|
|
||||||
if(log_out_fp == NULL) // 未设置输出文件
|
|
||||||
log_out_fp = stdout;
|
|
||||||
if(level < LOG_INFO || level > LOG_FATAL) // 日志等级不在范围内
|
|
||||||
PERROR("LOG: log_print level out of range !\n");
|
|
||||||
if(level < low_show_level) // 低于最低等级的log不进行打印
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(get_loghead() != 0) // 生成日志头
|
|
||||||
PERROR("LOG: log_print get_loghead error\n");
|
|
||||||
if(!fputs(log_head, log_out_fp)) // 打印日志头
|
|
||||||
PERROR("LOG: log_print fputs_head error\n");
|
|
||||||
|
|
||||||
switch(level) { // 打印错误等级
|
|
||||||
case LOG_INFO:
|
|
||||||
if(fputs("INFO:", log_out_fp))
|
|
||||||
break;
|
|
||||||
case LOG_WARNING:
|
|
||||||
if(fputs("WARNING:", log_out_fp))
|
|
||||||
break;
|
|
||||||
case LOG_ERROR:
|
|
||||||
if(fputs("ERROR:", log_out_fp))
|
|
||||||
break;
|
|
||||||
case LOG_FATAL:
|
|
||||||
if(fputs("FATAL:", log_out_fp))
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PERROR("LOG: log_print out level is untrue !\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!fputs(message, log_out_fp)) // 打印message
|
|
||||||
PERROR("LOG: log_head fputs fail !\n");
|
|
||||||
fputc('\n', log_out_fp);
|
|
||||||
log_number++; // 日志计数++
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
get_loghead(void) {
|
|
||||||
char buf[64];
|
|
||||||
time_t now_time = time(NULL);
|
|
||||||
clock_t core_time = clock() / CLOCKS_PER_SEC; // 以 s 为单位的 cpu 时间
|
|
||||||
struct tm *tm_time = localtime(&now_time);
|
|
||||||
int temp;
|
|
||||||
|
|
||||||
memset(log_head, '\0', sizeof(log_head)); // 重置日志头
|
|
||||||
|
|
||||||
for(int i = 0; i < strlen(log_head_format); i++) {
|
|
||||||
if(log_head_format[i] != '%') { // 非特殊字符则按正常复制
|
|
||||||
log_head[strlen(log_head)] = log_head_format[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
switch(log_head_format[i]) { // 特殊字符转换
|
|
||||||
case 'y' :
|
|
||||||
strftime(buf, 64, "%Y", tm_time);
|
|
||||||
break;
|
|
||||||
case 'm' :
|
|
||||||
strftime(buf, 64, "%m", tm_time);
|
|
||||||
break;
|
|
||||||
case 'd' :
|
|
||||||
strftime(buf, 64, "%d", tm_time);
|
|
||||||
break;
|
|
||||||
case 'h' :
|
|
||||||
strftime(buf, 64, "%H", tm_time);
|
|
||||||
break;
|
|
||||||
case 'M' :
|
|
||||||
strftime(buf, 64, "%M", tm_time);
|
|
||||||
break;
|
|
||||||
case 's' :
|
|
||||||
strftime(buf, 64, "%S", tm_time);
|
|
||||||
break;
|
|
||||||
case 'n' :
|
|
||||||
int_to_str(log_number, buf);
|
|
||||||
break;
|
|
||||||
case 'c' :
|
|
||||||
int_to_str(core_time, buf);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
strcat(log_head, buf);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
int_to_str(int num, char *restrict str) {
|
|
||||||
if(num < 0)
|
|
||||||
return; // 日志编号不可能小于 0
|
|
||||||
|
|
||||||
// 逐位提取数字(反向存储)
|
|
||||||
int start = 0;
|
|
||||||
do {
|
|
||||||
str[start++] = num % 10 + '0';
|
|
||||||
num /= 10;
|
|
||||||
} while (num > 0);
|
|
||||||
str[start] = '\0';
|
|
||||||
|
|
||||||
// 反转数字部分
|
|
||||||
char buf[16];
|
|
||||||
strncpy(buf, str, 16);
|
|
||||||
for(int i = 0; i < strlen(buf); i++)
|
|
||||||
str[--start] = buf[i];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef POINT_STR
|
|
||||||
#undef PERROR
|
|
@ -1,71 +0,0 @@
|
|||||||
// Copyright(c) 2025 Rangersly All rights reserved.
|
|
||||||
//
|
|
||||||
// function :
|
|
||||||
// Output log
|
|
||||||
//
|
|
||||||
// Author:
|
|
||||||
// Rangersly
|
|
||||||
//
|
|
||||||
// Versions:
|
|
||||||
// - 1.0 base function
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define LOG_INFO 0
|
|
||||||
#define LOG_WARNING 1
|
|
||||||
#define LOG_ERROR 2
|
|
||||||
#define LOG_FATAL 3
|
|
||||||
|
|
||||||
#define LOG_HEAD_MAX_FORMAT 32
|
|
||||||
|
|
||||||
// 如果未定义 NDEBUG 宏,错误发生时将打印错误信息
|
|
||||||
|
|
||||||
extern void
|
|
||||||
log_setoutfile(const char *restrict filename);
|
|
||||||
// 设置输出文件
|
|
||||||
// 默认输出为 stdout
|
|
||||||
|
|
||||||
extern void
|
|
||||||
log_setlevel(int level);
|
|
||||||
// 设置最低输出日志等级,低于最低等级的日志将忽略
|
|
||||||
|
|
||||||
extern void
|
|
||||||
log_sethead(const char *restrict head);
|
|
||||||
// 设置日志头,最大不可超过15个字符
|
|
||||||
// 符号表
|
|
||||||
// %y year
|
|
||||||
// %m month
|
|
||||||
// %d day
|
|
||||||
// %h hour
|
|
||||||
// %M minute
|
|
||||||
// %s second
|
|
||||||
// %n number
|
|
||||||
// %c core time .3f
|
|
||||||
|
|
||||||
extern void
|
|
||||||
log_print(int level, const char *restrict message);
|
|
||||||
// 输出日志 ^---等级 ^---输出信息
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// EXAMPLE
|
|
||||||
/*
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
log_setoutfile("log.out");
|
|
||||||
log_setlevel(LOG_ERROR);
|
|
||||||
log_sethead("#%d-%h-%M-%s-%n-%c#");
|
|
||||||
|
|
||||||
log_print(LOG_INFO, " hello");
|
|
||||||
log_print(LOG_WARNING, " hello");
|
|
||||||
log_print(LOG_ERROR, " hello");
|
|
||||||
log_print(LOG_FATAL, " hello");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
@ -15,6 +15,7 @@
|
|||||||
- [cpp fio](#cpp-fio)
|
- [cpp fio](#cpp-fio)
|
||||||
- [关闭缓冲区读取](#../linux/ncurses.c)
|
- [关闭缓冲区读取](#../linux/ncurses.c)
|
||||||
- [ANSI](#./ansi.md)
|
- [ANSI](#./ansi.md)
|
||||||
|
- [宏](#macro)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -215,3 +216,8 @@ ________________________________________________
|
|||||||
ios::end
|
ios::end
|
||||||
*/
|
*/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **macro**
|
||||||
|
- `BUFSIZ` : 系统级缓冲区大小
|
||||||
|
@ -35,8 +35,6 @@
|
|||||||
- [string hash](../libs/string_hash.c)
|
- [string hash](../libs/string_hash.c)
|
||||||
- [thread pool](../libs/thread-pool.cpp) : 简易线程池
|
- [thread pool](../libs/thread-pool.cpp) : 简易线程池
|
||||||
- [BIT](../libs/bit.h) : 有关位运算的函数封装
|
- [BIT](../libs/bit.h) : 有关位运算的函数封装
|
||||||
- [LOG](../libs/log/log.h) : 简单日志系统
|
|
||||||
- [dbtools](../libs/dbtools.h) : DEBUG工具集
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -319,7 +317,6 @@ struct tm {
|
|||||||
## **errno**
|
## **errno**
|
||||||
### **1. `errno` 全局变量**
|
### **1. `errno` 全局变量**
|
||||||
`extern int errno; // 声明全局错误变量`
|
`extern int errno; // 声明全局错误变量`
|
||||||
- 当标准库函数执行失败时,会设置 `errno` 为特定的错误码.
|
|
||||||
- **特点**
|
- **特点**
|
||||||
- 由系统或库函数自动设置,**程序启动时初始化为 0**(表示无错误).
|
- 由系统或库函数自动设置,**程序启动时初始化为 0**(表示无错误).
|
||||||
- **每个线程有独立的 `errno`**(多线程安全).
|
- **每个线程有独立的 `errno`**(多线程安全).
|
||||||
@ -355,21 +352,6 @@ struct tm {
|
|||||||
- `char *strerror(int errnum);`
|
- `char *strerror(int errnum);`
|
||||||
- 返回错误码对应的字符串描述.
|
- 返回错误码对应的字符串描述.
|
||||||
|
|
||||||
### **4. 使用场景**
|
|
||||||
- **(1) 文件操作错误处理**
|
|
||||||
- **(2) 数学函数错误处理**
|
|
||||||
- **(3) 动态内存分配错误**
|
|
||||||
|
|
||||||
### **5. 注意事项**
|
|
||||||
1. **`errno` 的线程安全性**:
|
|
||||||
- 在多线程环境中,`errno` 是线程局部的(每个线程独立维护).
|
|
||||||
2. **`errno` 的初始化**:
|
|
||||||
- 程序启动时 `errno` 为 0,调用成功**不会清零**(需手动重置).
|
|
||||||
3. **`errno` 的检查时机**:
|
|
||||||
- 必须在函数返回后**立即检查**,否则可能被后续操作覆盖.
|
|
||||||
4. **不可直接修改 `errno`**:
|
|
||||||
- 除非明确需要设置错误码,否则不应手动修改 `errno`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## **assert**
|
## **assert**
|
||||||
|
@ -6,48 +6,56 @@
|
|||||||
- [制作库文件](#make-lib)
|
- [制作库文件](#make-lib)
|
||||||
|
|
||||||
## **option**
|
## **option**
|
||||||
- `g++ -S test.s test.cpp` 编译成汇编文件
|
- `-S` : 编译成汇编文件
|
||||||
- `g++ -c test.o test.s` 目标文件
|
- `-c` : 目标文件
|
||||||
- `g++ -o test test.o` 链接
|
- `-o` : 链接
|
||||||
- `g++ -S -o - -fverbose-asm xxx.cpp > xxx.s` // 输出带注释的汇编
|
- `-g` : 调试
|
||||||
- `-D <MACRO_NAME>` 定义一个宏,默认值为1
|
- `-D <MACRO_NAME>` 定义一个宏,默认值为1
|
||||||
- `-U <MACRO_NAME>` 取消定义
|
- `-U <MACRO_NAME>` 取消定义
|
||||||
|
- `-l` : 链接库名称
|
||||||
|
- `-L` : 链接库位置
|
||||||
|
- `-I` : 头文件位置
|
||||||
|
- `-Wall` : 启动所有常见警告
|
||||||
|
- `-fPIC` : 生成位置无关代码
|
||||||
|
- `-MMD` : 自动生成`.d`文件,记录源文件与头文件的依赖关系,头文件修改后自动触发相关源文件重编译
|
||||||
|
|
||||||
- `gcc -s` 选项用于剥除可执行文件中的符号表和重定位信息,减小可执行文件的大小
|
- `gcc -s` 剥除可执行文件中的符号表和重定位信息
|
||||||
- **正常功能保持**
|
- **正常功能保持**
|
||||||
- **性能无显著差异**
|
- **性能无显著差异**
|
||||||
- **调试困难**:符号表中包含了函数名、变量名等调试信息。使用 `-s` 选项后,这些信息会被移除,使得调试变得非常困难
|
- **调试困难和反汇编不便** : 使用 `-s` 选项后,符号表信息会被移除,使得调试变得非常困难,反汇编工具无法显示函数名和变量名等信息,只能显示汇编指令和地址
|
||||||
- **反汇编和分析不便**:没有符号表,反汇编工具(如 `objdump`)无法显示函数名和变量名等信息,只能显示汇编指令和地址。这会增加对程序进行反汇编分析的难度。
|
- `g++ -S -o - -fverbose-asm xxx.cpp > xxx.s` // 输出带注释的汇编
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### **level**
|
### **level**
|
||||||
- **O0** 不进行任何优化
|
- **O0** 不进行任何优化
|
||||||
- **O1** 基础优化
|
- **O1** 基础优化
|
||||||
- 删除未使用的变量和函数
|
- 删除未使用的变量和函数
|
||||||
- 简化控制流(如合并重复代码)
|
- 简化控制流(如合并重复代码)
|
||||||
- 常量折叠(如 2+3 替换为 5)
|
- 常量折叠(如 2+3 替换为 5)
|
||||||
- 简单的寄存器分配
|
- 简单的寄存器分配
|
||||||
- **O2** 中等优化,推荐级别
|
- **O2** 中等优化,推荐级别
|
||||||
- 指令调度(提高指令级并行性)
|
- 指令调度(提高指令级并行性)
|
||||||
- 循环优化(如循环展开、循环不变代码外提)
|
- 循环优化(如循环展开、循环不变代码外提)
|
||||||
- 函数内联(简单函数直接展开)
|
- 函数内联(简单函数直接展开)
|
||||||
- 分支预测优化
|
- 分支预测优化
|
||||||
- 数据流分析优化
|
- 数据流分析优化
|
||||||
- **O3** 激进优化
|
- **O3** 激进优化
|
||||||
- 更激进的循环优化(如自动向量化,利用 SIMD 指令如 SSE/AVX)
|
- 更激进的循环优化(如自动向量化,利用 SIMD 指令如 SSE/AVX)
|
||||||
- 函数内联更积极(可能导致代码膨胀)
|
- 函数内联更积极(可能导致代码膨胀)
|
||||||
- 删除冗余内存访问
|
- 删除冗余内存访问
|
||||||
- 数学表达式重构(可能影响浮点精度)
|
- 数学表达式重构(可能影响浮点精度)
|
||||||
- **优化易导致的问题**
|
- **优化易导致的问题**
|
||||||
- 暴露未定义行为(Undefined Behavior, UB)
|
- 暴露未定义行为(Undefined Behavior, UB)
|
||||||
- 调试信息不匹配
|
- 调试信息不匹配
|
||||||
- 重新排列或合并浮点运算,导致精度损失
|
- 重新排列或合并浮点运算,导致精度损失
|
||||||
- 代码体积膨胀
|
- 代码体积膨胀
|
||||||
- 重排内存访问顺序,影响多线程程序或硬件寄存器操作
|
- 重排内存访问顺序,影响多线程程序或硬件寄存器操作
|
||||||
- 依赖时序的代码失效
|
- 依赖时序的代码失效
|
||||||
- 向量化(SIMD)导致的兼容性问题
|
- 向量化(SIMD)导致的兼容性问题
|
||||||
- 内联汇编的意外行为
|
- 内联汇编的意外行为
|
||||||
|
- **Os**
|
||||||
|
- 减小体积
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -56,25 +64,18 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 静态库制作:
|
### 静态库制作:
|
||||||
g++ -c -o libtest.a {test.cpp 源代码文件清单}
|
1. `g++ -c test.cpp`
|
||||||
// g++ -c test.cpp
|
2. `ar rcs libtest.a test.o`
|
||||||
// ar -crv libtest.a test.o
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 动态库制作
|
### 动态库制作
|
||||||
g++ -fPIC -shared -o libtest.so {test.cpp 源代码文件清单}
|
`g++ -fPIC -shared -o libtest.so {test.cpp 源代码文件清单}`
|
||||||
// g++ -fPIC -c test.cpp
|
|
||||||
// g++ -shared -o libtest.so tset.o
|
|
||||||
两种方法
|
|
||||||
1 + .so 放到 /usr/lib 或 /lib
|
|
||||||
2 + 路径放到/etc/ld.so.conf 运行ldconfd 重建/etc/ld.so.cache
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 库使用
|
### 库使用
|
||||||
g++ -o main -l库名 -L库路径 -I头文件路径
|
g++ -o main -l库名 -L库路径 -I头文件路径
|
||||||
// g++ -o main -ltest -L/home/e0x1a/test
|
|
||||||
|
|
||||||
#### 编译主程序时链接动态库
|
#### 编译主程序时链接动态库
|
||||||
- `gcc -o myprogram main.c -L. -lmylib -Wl,-rpath=.`
|
- `gcc -o myprogram main.c -L. -lmylib -Wl,-rpath=.`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user