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:
rangersly 2025-06-02 09:06:01 +08:00
parent b462e74945
commit d05beb0f1f
7 changed files with 74 additions and 325 deletions

View File

@ -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
---

View File

@ -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

View File

@ -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

View File

@ -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;
}
*/

View File

@ -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` : 系统级缓冲区大小

View File

@ -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**

View File

@ -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=.`