BIG MERGE!!!
BIG ADD: - docker - archlinux FIX: - vim - c_cpp - string hash - linux /dev/random - thread - STL - linux - command - last OTHERS: - add antenna.md - mirrors - makefile.md
This commit is contained in:
parent
7539960a7d
commit
93cecd7544
10
electronic/parameter.md
Normal file
10
electronic/parameter.md
Normal file
@ -0,0 +1,10 @@
|
||||
# 电子硬件参数
|
||||
|
||||
## 目录
|
||||
- [电阻](#电阻)
|
||||
- [电容](#电容)
|
||||
- [电感](#电感)
|
||||
- [微控制器](#微控制器)
|
||||
- [逻辑器件](#逻辑器件)
|
||||
- [晶体管](#晶体管)
|
||||
|
0
miscellaneous/README.md
Normal file
0
miscellaneous/README.md
Normal file
19
os/linux/arch/command.md
Normal file
19
os/linux/arch/command.md
Normal file
@ -0,0 +1,19 @@
|
||||
# arch常用命令
|
||||
|
||||
- [pacman](#pacman)
|
||||
|
||||
|
||||
## pacman
|
||||
|
||||
+ `-S` 同步
|
||||
+ `-y` 更新软件包数据库
|
||||
+ `-u` 升级已有安装包
|
||||
+ `-R` 卸载
|
||||
+ `-Q` 查看已安装
|
||||
> 示例
|
||||
+ `pacman -Sy` 同步数据库
|
||||
+ `pacman -S <package_name>` 安装软件包
|
||||
+ `pacman -Syu` 更新系统
|
||||
+ `pacman -Rs <package_name>` 卸载同时删除无用的依赖
|
||||
+ `pacman -Ss <keyword>` 搜索软件包
|
||||
+ `sudo pacman -Sc` 清除缓存
|
125
os/linux/arch/install.md
Normal file
125
os/linux/arch/install.md
Normal file
@ -0,0 +1,125 @@
|
||||
# archlinux安装
|
||||
|
||||
## 目录
|
||||
- [基础安装](#基础安装)
|
||||
- [修改控制台字体](#修改控制台字体)
|
||||
- [验证引导](#验证引导)
|
||||
- [验证网络和更改系统时间](#验证网络和更改系统时间)
|
||||
- [硬盘分区](#硬盘分区)
|
||||
- [安装基础软件包](#安装基础软件包)
|
||||
- [生成fstab](#生成fstab)
|
||||
- [chroot配置](#chroot)
|
||||
- [新系统](#新系统)
|
||||
- [换源](#换源)
|
||||
- [普通用户](#普通用户)
|
||||
- [KDE](#kde)
|
||||
|
||||
## 基础安装
|
||||
|
||||
### 修改控制台字体
|
||||
|
||||
`/usr/share/kbd/consolefonts/` 存放字体的位置
|
||||
`# setfont ter-132b`
|
||||
|
||||
### 验证引导
|
||||
|
||||
`# cat /sys/firmware/efi/fw_platform_size`
|
||||
|
||||
### 验证网络和更改系统时间
|
||||
|
||||
`ip addr`
|
||||
`timedatectl`
|
||||
|
||||
### 硬盘分区
|
||||
|
||||
```bash
|
||||
parted /dev/sdX # 进入parted交互界面
|
||||
> mklabel gpt # 创建分区表格式
|
||||
|
||||
gdisk /dev/sdX # 分区
|
||||
ef00 -> 1G
|
||||
ef02 -> 2M
|
||||
8300 -> /
|
||||
|
||||
**先用最小系统启动**
|
||||
|
||||
mkfs.fat -F 32 /dev/sdX1 # 分区格式化
|
||||
mkfs.ext4 /dev/sdX3
|
||||
|
||||
mount /dev/sdX3 /mnt
|
||||
mount --mkdir /dev/sdX1 /mnt/boot
|
||||
```
|
||||
|
||||
### 安装基础软件包
|
||||
|
||||
`pacstrap -K /mnt xxx`
|
||||
+ base linux linux-firmware
|
||||
+ vim base-devel networkmanager archlinuxcn-keyring
|
||||
---
|
||||
以下是可以等系统启动后安装的
|
||||
+ sof-firmware
|
||||
+ yay
|
||||
`pacman -S git base-devel && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si`
|
||||
+ man
|
||||
+ fcitx5-im fcitx5-rime # 输入法
|
||||
+ alsa-utils # 声卡驱动
|
||||
+ 其他固件
|
||||
|
||||
### 生成fstab
|
||||
|
||||
`genfstab -U /mnt > /mnt/etc/fstab`
|
||||
|
||||
### chroot
|
||||
|
||||
```bash
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 配置时间
|
||||
hwclock --systohc
|
||||
|
||||
vim /etc/locale.gen
|
||||
> 去掉 en_GB.UTF-8 以及 zh_CN.
|
||||
locale-gen
|
||||
vim /etc/locale.conf
|
||||
> LANG=en_US.UTF-8
|
||||
|
||||
vim /etc/hostname
|
||||
> [hostname]
|
||||
|
||||
passwd
|
||||
|
||||
**安装引导**
|
||||
pacman -S grub
|
||||
grub-install --target=i386-pc /dev/sdX
|
||||
grub-mkconfig -o /boot/grub/grub.cfg
|
||||
|
||||
umount -R /mnt
|
||||
|
||||
reboot
|
||||
```
|
||||
|
||||
## 新系统
|
||||
|
||||
### 换源
|
||||
- `/etc/pacman.d/mirrorlist`
|
||||
```
|
||||
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
|
||||
Server = http://mirrors.aliyun.com/archlinux/$repo/os/$arch
|
||||
Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
|
||||
```
|
||||
|
||||
### 普通用户
|
||||
|
||||
`useradd -m -G wheel username`
|
||||
`vim /etc/sudoers`
|
||||
|
||||
### kde
|
||||
|
||||
```
|
||||
pacman -S noto-fonts noto-fonts-cjk noto-fonts-emoji # 安装字体
|
||||
pacman -S plasma
|
||||
systemctl enable sddm
|
||||
|
||||
cd ~/.local/share/fcitx5/rime # 配置输入法
|
||||
git clone https://github.com/iDvel/rime-ice.git
|
||||
cp -r ./rime-ice/* .
|
||||
|
||||
sudo usermod -a -G uucp $USER # 允许用户使用串口
|
1321
os/linux/command.md
1321
os/linux/command.md
File diff suppressed because it is too large
Load Diff
@ -1,117 +0,0 @@
|
||||
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||
# for examples
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
case $- in
|
||||
*i*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
|
||||
# don't put duplicate lines or lines starting with space in the history.
|
||||
# See bash(1) for more options
|
||||
HISTCONTROL=ignoreboth
|
||||
|
||||
# append to the history file, don't overwrite it
|
||||
shopt -s histappend
|
||||
|
||||
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
||||
HISTSIZE=500
|
||||
HISTFILESIZE=500
|
||||
|
||||
# check the window size after each command and, if necessary,
|
||||
# update the values of LINES and COLUMNS.
|
||||
shopt -s checkwinsize
|
||||
|
||||
# If set, the pattern "**" used in a pathname expansion context will
|
||||
# match all files and zero or more directories and subdirectories.
|
||||
#shopt -s globstar
|
||||
|
||||
# make less more friendly for non-text input files, see lesspipe(1)
|
||||
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||
|
||||
# set variable identifying the chroot you work in (used in the prompt below)
|
||||
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
|
||||
debian_chroot=$(cat /etc/debian_chroot)
|
||||
fi
|
||||
|
||||
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||
case "$TERM" in
|
||||
xterm-color|*-256color) color_prompt=yes;;
|
||||
esac
|
||||
|
||||
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||
# off by default to not distract the user: the focus in a terminal window
|
||||
# should be on the output of commands, not on the prompt
|
||||
#force_color_prompt=yes
|
||||
|
||||
if [ -n "$force_color_prompt" ]; then
|
||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||
# We have color support; assume it's compliant with Ecma-48
|
||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||
# a case would tend to support setf rather than setaf.)
|
||||
color_prompt=yes
|
||||
else
|
||||
color_prompt=
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$color_prompt" = yes ]; then
|
||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h@\t\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||
else
|
||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h@\t:\w\$ '
|
||||
fi
|
||||
unset color_prompt force_color_prompt
|
||||
|
||||
# If this is an xterm set the title to user@host:dir
|
||||
case "$TERM" in
|
||||
xterm*|rxvt*)
|
||||
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h@\t: \w\a\]$PS1"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# enable color support of ls and also add handy aliases
|
||||
if [ -x /usr/bin/dircolors ]; then
|
||||
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||
alias ls='ls --color=auto'
|
||||
#alias dir='dir --color=auto'
|
||||
#alias vdir='vdir --color=auto'
|
||||
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
fi
|
||||
|
||||
# colored GCC warnings and errors
|
||||
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
|
||||
|
||||
# some more ls aliases
|
||||
alias ll='ls -ahlF'
|
||||
alias l='ls -lF'
|
||||
# Add an "alert" alias for long running commands. Use like so:
|
||||
# sleep 10; alert
|
||||
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
||||
|
||||
# Alias definitions.
|
||||
# You may want to put all your additions into a separate file like
|
||||
# ~/.bash_aliases, instead of adding them here directly.
|
||||
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
||||
|
||||
if [ -f ~/.bash_aliases ]; then
|
||||
. ~/.bash_aliases
|
||||
fi
|
||||
|
||||
# enable programmable completion features (you don't need to enable
|
||||
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||
# sources /etc/bash.bashrc).
|
||||
if ! shopt -oq posix; then
|
||||
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||
. /usr/share/bash-completion/bash_completion
|
||||
elif [ -f /etc/bash_completion ]; then
|
||||
. /etc/bash_completion
|
||||
fi
|
||||
fi
|
||||
alias powerele="upower -i /org/freedesktop/UPower/devices/battery_BAT0"
|
||||
export LANG=en_US.UTF-8
|
@ -1,27 +0,0 @@
|
||||
# ~/.profile: executed by the command interpreter for login shells.
|
||||
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
||||
# exists.
|
||||
# see /usr/share/doc/bash/examples/startup-files for examples.
|
||||
# the files are located in the bash-doc package.
|
||||
|
||||
# the default umask is set in /etc/profile; for setting the umask
|
||||
# for ssh logins, install and configure the libpam-umask package.
|
||||
#umask 022
|
||||
|
||||
# if running bash
|
||||
if [ -n "$BASH_VERSION" ]; then
|
||||
# include .bashrc if it exists
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
. "$HOME/.bashrc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# set PATH so it includes user's private bin if it exists
|
||||
if [ -d "$HOME/bin" ] ; then
|
||||
PATH="$HOME/bin:$PATH"
|
||||
fi
|
||||
|
||||
# set PATH so it includes user's private bin if it exists
|
||||
if [ -d "$HOME/.local/bin" ] ; then
|
||||
PATH="$HOME/.local/bin:$PATH"
|
||||
fi
|
252
program/c_cpp/STL/algorithms.md
Normal file
252
program/c_cpp/STL/algorithms.md
Normal file
@ -0,0 +1,252 @@
|
||||
# STL算法
|
||||
|
||||
## 目录
|
||||
- [非修改性算法](#)
|
||||
- [find](#)
|
||||
- [conut](#)
|
||||
- [二分查找](#binary-search)
|
||||
- [修改性算法](#)
|
||||
- [copy](#)
|
||||
- [replace](#):将指定范围内等于给定值的元素替换为新值
|
||||
- [reverse](#):翻转序列
|
||||
- [排序算法](#)
|
||||
- [sort](#)
|
||||
- [稳定排序](#stable-sort)
|
||||
- [第n大数](#nth-element)
|
||||
- [数值算法](#)
|
||||
- [accumulate](#):计算指定范围内元素的累积和
|
||||
- [计算两个序列的内积](#inner-product)
|
||||
- [集合算法](#)
|
||||
- [两个有序序列的差集](#set-difference)
|
||||
- [将两个有序序列合并为一个有序序列](#merge)
|
||||
- [其他算法](#)
|
||||
- [去除相邻重复元素](#unique)
|
||||
- [随机打乱序列](#shuffle)
|
||||
|
||||
## 非修改性算法
|
||||
### find
|
||||
```
|
||||
template <class InputIterator, class T>
|
||||
InputIterator find(InputIterator first, InputIterator last, const T& value);
|
||||
```
|
||||
+ InputIterator:输入迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||
+ value:要查找的目标值。
|
||||
+ 返回值:如果找到目标值,返回指向该元素的迭代器;如果没有找到,则返回 last
|
||||
|
||||
__注意事项__
|
||||
1. 返回值的判断
|
||||
如果未找到目标值,返回值是 last,通常需要通过比较返回值是否等于 last 来判断是否找到目标
|
||||
|
||||
2. 自定义对象的比较
|
||||
如果要在自定义对象中使用 `std::find`,需要重载 `operator==`,以便算法能够比较对象是否相等
|
||||
|
||||
3. 性能
|
||||
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
|
||||
|
||||
4. 范围的正确性
|
||||
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
|
||||
|
||||
### conut
|
||||
```
|
||||
template <class InputIterator, class T>
|
||||
typename iterator_traits<InputIterator>::difference_type count(
|
||||
InputIterator first,
|
||||
InputIterator last,
|
||||
const T& value
|
||||
);
|
||||
```
|
||||
+ InputIterator:输入迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||
+ value:要统计的目标值。
|
||||
+ 返回值:返回等于目标值的元素个数,类型为 `iterator_traits<InputIterator>::difference_type`
|
||||
|
||||
__注意事项__
|
||||
1. 返回值的判断
|
||||
返回值类型是 `iterator_traits<InputIterator>::difference_type`,通常是与容器相关的整数类型 `int` `size_t`
|
||||
|
||||
2. 自定义对象的比较
|
||||
需要重载 `operator==`,以便算法能够比较对象是否相等
|
||||
|
||||
3. 性能
|
||||
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
|
||||
|
||||
4. 范围的正确性
|
||||
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
|
||||
|
||||
### binary-search
|
||||
用于在*有序序列*中查找是否存在某个值,基于二分查找的思想,时间复杂度为 O(log n)
|
||||
|
||||
只返回布尔值,表示是否找到目标值,如果需要找到目标值的位置,可以结合 `std::lower_bound` 或 `std::upper_bound` 使用
|
||||
```
|
||||
template <class ForwardIterator, class T>
|
||||
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value);
|
||||
```
|
||||
+ ForwardIterator:正向迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||
+ value:要查找的目标值。
|
||||
+ 返回值:如果找到目标值,返回 true;否则返回 false。
|
||||
|
||||
__还支持自定义比较函数__
|
||||
```
|
||||
template <class ForwardIterator, class T, class Compare>
|
||||
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);
|
||||
```
|
||||
+ Compare:比较函数,用于定义元素之间的大小关系。如果未提供,会使用默认的 < 比较运算符
|
||||
|
||||
## 修改性算法
|
||||
### copy
|
||||
用于将一个范围内的元素复制到另一个范围中,是一个线性算法,时间复杂度为 O(n)
|
||||
|
||||
```
|
||||
template <class InputIterator, class OutputIterator>
|
||||
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);
|
||||
```
|
||||
+ InputIterator:输入迭代器类型,表示要复制的源范围的起始和结束位置。
|
||||
+ first:指向源范围的起始位置的迭代器。
|
||||
+ last:指向源范围的结束位置的迭代器(不包含)。
|
||||
+ OutputIterator:输出迭代器类型,表示目标范围的起始位置。
|
||||
+ result:指向目标范围的起始位置的迭代器。
|
||||
+ 返回值:返回指向目标范围结束位置的迭代器(即 result + (last - first))
|
||||
|
||||
### replace
|
||||
用于在指定范围内将所有等于某个特定值的元素替换为另一个值
|
||||
|
||||
```
|
||||
template <class ForwardIterator, class T>
|
||||
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);
|
||||
```
|
||||
+ ForwardIterator:正向迭代器类型,表示要操作的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||
+ `old_value`:要被替换的旧值。
|
||||
+ `new_value`:用于替换的新值。
|
||||
|
||||
如果需要更复杂的替换逻辑(例如基于条件的替换),可以结合 `std::replace_if` 使用,后者允许传入一个谓词函数来定义替换条件。
|
||||
|
||||
### reverse
|
||||
反转指定范围内的元素顺序,要求输入范围的迭代器是双向迭代器,即支持双向遍历
|
||||
|
||||
```
|
||||
template <class BidirectionalIterator>
|
||||
void reverse(BidirectionalIterator first, BidirectionalIterator last);
|
||||
```
|
||||
+ BidirectionalIterator:双向迭代器类型,表示要反转的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)
|
||||
|
||||
## 排序算法
|
||||
### sort
|
||||
指定范围内的元素进行排序,要求输入范围的迭代器是随机访问迭代器,是不稳定的排序算法,平均时间复杂度为 O(n log n)
|
||||
|
||||
```
|
||||
template <class RandomAccessIterator>
|
||||
void sort(RandomAccessIterator first, RandomAccessIterator last);
|
||||
```
|
||||
+ RandomAccessIterator:随机访问迭代器类型,表示要排序的范围的起始和结束位置
|
||||
+ first:指向范围的起始位置的迭代器
|
||||
+ last:指向范围的结束位置的迭代器(不包含)
|
||||
|
||||
此外,std::sort 还支持自定义比较函数
|
||||
```
|
||||
template <class RandomAccessIterator, class Compare>
|
||||
void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
|
||||
```
|
||||
|
||||
### stable-sort
|
||||
是一个稳定排序算法,对指定范围内的元素进行排序,同时保证相等元素的相对顺序不变
|
||||
|
||||
```
|
||||
template <class RandomAccessIterator>
|
||||
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
|
||||
|
||||
template <class RandomAccessIterator, class Compare>
|
||||
void stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
|
||||
```
|
||||
+ first 和 last:随机访问迭代器,分别指向要排序范围的起始位置和结束位置(不包含)
|
||||
+ Compare:可选的比较函数,用于定义排序规则。如果未提供,默认使用 < 运算符
|
||||
|
||||
如果有足够的额外内存,`std::stable_sort` 的时间复杂度为 O(n log n),内存不足,时间复杂度可能退化为 O(n log² n)
|
||||
|
||||
|
||||
### nth-element
|
||||
用于部分排序序列,使得第 k 小的元素被放置到正确的位置,同时保证所有在它之前的元素都不大于它,所有在它之后的元素都不小于它,平均时间复杂度:O(n),最坏时间复杂度:O(n²)
|
||||
|
||||
```
|
||||
template <class RandomIt>
|
||||
void nth_element(RandomIt first, RandomIt nth, RandomIt last);
|
||||
|
||||
template <class RandomIt, class Compare>
|
||||
void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp);
|
||||
```
|
||||
+ first:指向序列起始位置的随机访问迭代器。
|
||||
+ nth:指向序列中第 k 个位置的迭代器(0-based index)。
|
||||
+ last:指向序列结束位置的迭代器。
|
||||
+ comp(可选):自定义比较函数,默认使用 std::less
|
||||
|
||||
> 不会完全排序整个序列,它只保证第 k 小的元素在正确的位置上
|
||||
> 该算法的性能优于完全排序
|
||||
|
||||
## 数值算法
|
||||
### accumulate
|
||||
用于计算指定范围内元素的累积和,时间复杂度为 O(n)
|
||||
|
||||
`std::accumulate` 从 first 开始,逐个处理范围内的元素,将每个元素与累积结果进行操作(默认为加法),并将最终结果返回
|
||||
|
||||
```
|
||||
template <class InputIterator, class T>
|
||||
T accumulate(InputIterator first, InputIterator last, T init);
|
||||
|
||||
template <class InputIterator, class T, class BinaryOperation>
|
||||
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation op);
|
||||
```
|
||||
+ InputIterator:输入迭代器类型,表示要操作的范围的起始和结束位置。
|
||||
+ first:指向范围的起始位置的迭代器。
|
||||
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||
+ T:累积结果的类型。
|
||||
+ init:初始值,用于开始累积操作。
|
||||
+ BinaryOperation(可选):二元操作函数,用于定义累积操作。如果未提供,默认使用加法操作 `std::plus<T>` [预定义函数符](./containers.md#)
|
||||
|
||||
### inner-product
|
||||
|
||||
## 集合算法
|
||||
### set-difference
|
||||
### merge
|
||||
|
||||
## 其他算法
|
||||
### unique
|
||||
用于移除序列中相邻的重复元素,并返回一个指向“新序列”结束位置的迭代器。它不会改变原序列的长度,而是将重复元素移动到序列末尾,并返回一个指向“有效部分”结束位置的迭代器。因此,通常需要结合容器的 erase 方法来真正移除重复元素,O(n)
|
||||
|
||||
```
|
||||
template <class ForwardIterator>
|
||||
ForwardIterator unique(ForwardIterator first, ForwardIterator last);
|
||||
|
||||
template <class ForwardIterator, class BinaryPredicate>
|
||||
ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred);
|
||||
```
|
||||
+ ForwardIterator:正向迭代器类型,表示要操作的序列的起始和结束位置。
|
||||
+ first:指向序列起始位置的迭代器。
|
||||
+ last:指向序列结束位置的迭代器(不包含)。
|
||||
+ BinaryPredicate(可选):二元谓词函数,用于定义两个元素是否相等。如果未提供,默认使用 operator==
|
||||
|
||||
### shuffle
|
||||
随机打乱指定范围内元素的顺序
|
||||
|
||||
```
|
||||
template <class RandomAccessIterator, class URNG>
|
||||
void shuffle(RandomAccessIterator first, RandomAccessIterator last, URNG&& g);
|
||||
```
|
||||
+ first 和 last:随机访问迭代器,分别指向要打乱范围的起始位置和结束位置(不包含)
|
||||
+ URNG:均匀随机数生成器,例如 `std::mt19937` 或 `std::default_random_enginei`
|
||||
|
||||
```
|
||||
// 使用随机数生成器
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
std::mt19937 rng(seed);
|
||||
|
||||
// 打乱顺序
|
||||
std::shuffle(vec.begin(), vec.end(), rng);
|
||||
```
|
240
program/c_cpp/STL/containers.md
Normal file
240
program/c_cpp/STL/containers.md
Normal file
@ -0,0 +1,240 @@
|
||||
# STL 容器
|
||||
|
||||
## 目录
|
||||
|
||||
- [概念](#)
|
||||
- [通性](#)
|
||||
- [序列容器](#)
|
||||
- [vector](#)
|
||||
- [deque](#)
|
||||
- [list](#)
|
||||
- [关联容器](#)
|
||||
- [set](#)
|
||||
- [multiset](#)
|
||||
- [map](#)
|
||||
- [multimap](#)
|
||||
- [无序容器](#)
|
||||
- [`unordered_set`](#unordered_set)
|
||||
- [`unordered_multiset`](#unordered_multiset)
|
||||
- [`unordered_map`](#unordered_map)
|
||||
- [`unordered_multimap`](#unordered_multimap)
|
||||
- [预定义函数符](#)
|
||||
|
||||
## 概念
|
||||
|
||||
**函数符**概念
|
||||
|
||||
其实就是重载了()的伪函数
|
||||
|
||||
- 生成器:无参数
|
||||
- 一元函数:一个参数
|
||||
- 二元函数:两个参数
|
||||
- 谓词:返回bool的一元函数
|
||||
- 二元谓词:返回bool的二元函数
|
||||
|
||||
## 通性
|
||||
|
||||
+ `begin()` 和 `end()` 用于获取容器的迭代器,指向容器的第一个元素和最后一个元素的“后继”
|
||||
+ `rbegin()` 和 `rend()` 用于获取容器的反向迭代器,指向容器的最后一个元素和第一个元素的“前驱”位置
|
||||
+ `size()` 返回容器中元素的数量
|
||||
+ `empty()` 如果容器为空,返回true;否则返回false
|
||||
+ `max_size()` 返回容器可能存储的最大元素数量
|
||||
+ `clear()` 清空容器中的所有元素,但不释放内存
|
||||
+ `swap()` 交换两个容器的内容
|
||||
+ `data()` **仅适用于序列容器** 返回指向容器底层存储的指针
|
||||
+ 提供对容器底层数据的直接访问
|
||||
+ 适用于需要与C语言风格的API交互的场景
|
||||
+ `front()` 和 `back()` **仅适用于序列容器** 返回容器的第一个元素和最后一个元素的引用
|
||||
+ `operator[]` 和 `at()` **仅适用于序列容器** 访问容器中的特定元素
|
||||
+ at() 进行边界检查,如果索引超出范围,会抛出`std::out_of_range`异常
|
||||
|
||||
## 序列容器
|
||||
|
||||
存储元素的顺序与插入顺序一致
|
||||
|
||||
### vector
|
||||
|
||||
1. 定义和初始化
|
||||
|
||||
`std::vector<int> vec1; // 定义一个空的 vector`
|
||||
`std::vector<int> vec2 = {1, 2, 3, 4, 5}; // 使用初始化列表初始化`
|
||||
`std::vector<int> vec3(10, 0); // 10个元素,初始值为0`
|
||||
`std::vector<int> vec4(vec2); // 拷贝构造`
|
||||
`std::vector<int> vec5(std::move(vec2)); // 移动构造`
|
||||
|
||||
2. 元素访问
|
||||
|
||||
支持序列容器的大部分访问方法
|
||||
|
||||
3. 修改容器
|
||||
|
||||
`push_back()` 在容器末尾添加一个元素
|
||||
`pop_back()` 删除容器末尾的元素
|
||||
`insert()` 在指定位置插入一个或多个元素
|
||||
`erase()` 删除指定位置的元素
|
||||
|
||||
4. 容量和大小
|
||||
|
||||
`capacity()` 返回容器当前分配的内存容量(以元素数量计)
|
||||
`reserve()` 预分配内存,减少动态扩展的次数
|
||||
`shrink_to_fit()` 收缩内存,释放多余空间
|
||||
|
||||
__使用技巧__
|
||||
|
||||
1. 预分配内存
|
||||
|
||||
如果知道容器将存储大量元素,可以使用 reserve() 预分配内存,以减少动态扩展的次数
|
||||
|
||||
2. 使用 `std::move()`
|
||||
|
||||
`vec2.push_back(std::move(vec1[0])); // 将vec1的第一个元素移动到vec2`
|
||||
|
||||
3. 使用vector的bool值特性
|
||||
|
||||
`std::vector<bool>` 是一个特化版本,它使用位存储来优化空间占用,但可能会牺牲某些操作的性能
|
||||
|
||||
4. 使用 `std::vector` 的指针特性
|
||||
|
||||
如果需要存储动态分配的对象,可以使用 `std::vector<std::unique_ptr<T>>` 或 `std::vector<std::shared_ptr<T>>`
|
||||
|
||||
|
||||
__vector 的 capacity 和 size 属性区别__
|
||||
|
||||
size 是当前 vector 容器真实占用的大小,也就是容器当前拥有多少个容器。
|
||||
|
||||
capacity 是指在发生 realloc 前能允许的最大元素数,即预分配的内存空间。
|
||||
|
||||
使用 resize() 容器内的对象内存空间是真正存在的。
|
||||
|
||||
使用 reserve() 仅仅只是修改了 capacity 的值,容器内的对象并没有真实的内存空间(空间是"野"的)。
|
||||
|
||||
### deque
|
||||
1. 插入和删除
|
||||
+ `push_back()` 和 `pop_back()`:尾部操作
|
||||
+ `push_front()` 和 `pop_front()`:头部操作
|
||||
+ `insert()` 和 `erase()`:在任意位置插入或删除
|
||||
|
||||
2. 大小操作
|
||||
+ `resize()`:调整容器大小
|
||||
|
||||
__使用技巧__
|
||||
> 高效头部操作:`deque` 是处理头部和尾部频繁插入删除的理想选择
|
||||
> 随机访问优化:虽然 `deque` 的内存不连续,但通过下标访问效率较高
|
||||
> 排序:由于支持随机访问,可以使用 `std::sort` 对 `deque` 进行排序
|
||||
> 迭代器失效:在添加或删除元素后,迭代器可能失效,需要重新获取
|
||||
|
||||
__注意事项__
|
||||
> 内存不连续:`deque` 的元素可能分散在多个内存块中,但通过下标或迭代器访问不会受到影响
|
||||
> 迭代器失效:在容器大小发生变化时(如插入或删除元素),迭代器可能会失效
|
||||
> 性能权衡:虽然 `deque` 在头部和尾部操作高效,但在中间插入或删除元素的性能不如 `list`
|
||||
|
||||
__相比vector的优势__
|
||||
> 头部操作高效:deque 在头部插入和删除操作的时间复杂度为 O(1),而 vector 为 O(n)。
|
||||
> 动态变化灵活:deque 的*分块内存*分配使其更灵活,性能损耗更小,且内存不足时不用搬运所有元素
|
||||
> 随机访问性能接近:虽然 deque 的随机访问效率略低于 vector,但差距不大
|
||||
|
||||
### list
|
||||
1. 特点
|
||||
+ 双向链表结构:每个元素包含指向前后元素的指针,支持双向遍历
|
||||
+ 高效插入和删除:在任意位置插入或删除元素的时间复杂度为 O(1),前提是已知位置
|
||||
+ 不支持随机访问:无法通过索引直接访问元素,只能通过迭代器遍历
|
||||
+ 稳定的迭代器:插入和删除操作不会使迭代器失效,除非删除了迭代器所指向的元素
|
||||
|
||||
1. 插入和删除
|
||||
+ `push_back()` 和 `pop_back()`:尾部操作
|
||||
+ `push_front()` 和 `pop_front()`:头部操作
|
||||
+ `insert()` 和 `erase()`:在任意位置插入或删除
|
||||
|
||||
2. 其他
|
||||
+ resize():调整容器大小
|
||||
+ swap():交换两个 list 的内容
|
||||
+ splice():将一个 list 的元素插入到另一个 list 的指定位置
|
||||
+ sort()、merge()、reverse():排序、合并和反转
|
||||
|
||||
__注意事项__
|
||||
> 不支持随机访问:无法通过索引访问元素,只能通过迭代器
|
||||
> 内存开销:每个元素存储额外的指针,内存开销较大
|
||||
> 缓存局部性差:元素不连续存储,遍历性能不如 std::vector
|
||||
> 适用场景有限:只有在需要频繁中间插入和删除时才适合使用
|
||||
|
||||
|
||||
## 关联容器
|
||||
|
||||
存储元素时会自动排序,通常基于键值对
|
||||
|
||||
### set
|
||||
基于红黑树实现 适用于需要去重、排序和*高效查找*的场景
|
||||
|
||||
1. 特点
|
||||
+ 元素唯一性:容器中不允许存储重复元素
|
||||
+ 自动排序:元素会根据指定的比较规则自动排序,默认为升序
|
||||
+ 高效查找:插入、删除和查找操作的时间复杂度均为 O(log n)
|
||||
|
||||
2. 构造与初始化
|
||||
+ 默认构造
|
||||
+ 初始化列表
|
||||
+ 拷贝构造
|
||||
+ 自定义比较规则
|
||||
```
|
||||
struct Compare {
|
||||
bool operator()(int a, int b) const {
|
||||
return a > b; // 降序排序
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
3. 常用操作
|
||||
+ 插入元素 `s1.insert(5);`
|
||||
+ 删除元素 `s1.erase(3); // 删除值为 3 的元素`
|
||||
+ 查找元素 `s1.find(4); // 返回指向元素的迭代器,未找到时返回 s1.end()`
|
||||
+ 统计元素 `int count = s1.count(4);`
|
||||
+ 范围查询
|
||||
```
|
||||
auto lower = s1.lower_bound(3); // 返回第一个 >= 3 的元素的迭代器
|
||||
auto upper = s1.upper_bound(5); // 返回第一个 > 5 的元素的迭代器
|
||||
```
|
||||
|
||||
4. 高级用法
|
||||
+ 自定义排序规则:使用仿函数或 `std::greater` 可以改变排序规则
|
||||
+ 存储复杂数据类型:可以存储 `std::pair` 或自定义结构体,通过自定义比较函数排序
|
||||
+ 范围删除 `s1.erase(s1.lower_bound(10), s1.upper_bound(50)); // 删除值在 [10, 50) 范围内的所有元素`
|
||||
|
||||
__注意事项__
|
||||
> 修改元素:无法直接修改容器中的元素值,需要先删除再插入
|
||||
> 性能开销:由于自动排序的特性,插入和删除操作比无序容器慢
|
||||
> 迭代器失效:插入操作不会使迭代器失效,但删除操作会使指向被删除元素的迭代器失效
|
||||
|
||||
### map
|
||||
用于存储键值对(key-value pairs),并根据键自动排序
|
||||
|
||||
1. 特点
|
||||
+ 键的唯一性:每个键在 map 中是唯一的,不允许重复
|
||||
+ 自动排序:容器会根据键的默认比较规则(通常是 < 运算符)自动排序
|
||||
+ 高效操作:插入、删除和查找操作的时间复杂度均为 O(log n),其中 n 是容器中元素的数量
|
||||
|
||||
2. 常用操作
|
||||
+ 插入元素:`map1.insert({4, "four"});`或`map1[5] = "five"; // 如果键不存在,则插入新键值对;如果键存在,则更新值`
|
||||
+ 查找元素:`map1.find(3);` 或者使用 `operator[]` 直接访问键对应的值
|
||||
+ 删除元素:`map1.erase(3); // 删除键为 3 的元素。`
|
||||
|
||||
## 无序容器
|
||||
|
||||
存储元素时不排序,基于哈希表实现
|
||||
|
||||
## 预定义函数符
|
||||
|
||||
+ `+` plus
|
||||
+ `-` minus
|
||||
+ `*` multiplies
|
||||
+ `/` divides
|
||||
+ `%` modulus
|
||||
|
||||
+ `==` `equal_to`
|
||||
+ `!=` `not_equal_to`
|
||||
+ `>` `greater`
|
||||
+ `<` `less`
|
||||
+ `>=` `greater_equal`
|
||||
+ `<=` `less_equal`
|
||||
+ `&&` `logical_and`
|
||||
+ `||` `logical_or`
|
||||
+ `!` `logical_not`
|
@ -87,5 +87,5 @@
|
||||
|
||||
## 神奇转换函数
|
||||
```cpp
|
||||
string to_ strinf(任何类型); //将好多类型转换成string
|
||||
string to_strinf(任何类型); //将好多类型转换成string
|
||||
```
|
2
program/c_cpp/library/offsetof.h
Normal file
2
program/c_cpp/library/offsetof.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define offsetof(type, struct_name) (size_t)&(((struct type*)0)->struct_name)
|
||||
// 计算结构体成员相对结构体首地址的偏移度
|
10
program/c_cpp/library/string_hash.c
Normal file
10
program/c_cpp/library/string_hash.c
Normal file
@ -0,0 +1,10 @@
|
||||
// 非加密型hash,速度极快,支持种子
|
||||
uint32_t murmur3_32(const char *key, size_t len, uint32_t seed) {
|
||||
for(uint32_t i=0; i<len; i++)
|
||||
{
|
||||
seed ^= (const uint8_t)key[i];
|
||||
seed *= 0x5bd1e995;
|
||||
seed ^= seed>> 15;
|
||||
}
|
||||
return seed;
|
||||
}
|
73
program/c_cpp/library/thread-pool.cpp
Normal file
73
program/c_cpp/library/thread-pool.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
ThreadPool(size_t num_threads);
|
||||
~ThreadPool();
|
||||
void enqueue(std::function<void()> task);
|
||||
|
||||
private:
|
||||
std::vector<std::thread> workers;
|
||||
std::queue<std::function<void()>> tasks;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
ThreadPool::ThreadPool(size_t num_threads) : stop(false) {
|
||||
for (size_t i = 0; i < num_threads; ++i) {
|
||||
workers.emplace_back([this] {
|
||||
while (true) {
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
|
||||
if (this->stop && this->tasks.empty()) {
|
||||
return;
|
||||
}
|
||||
task = std::move(this->tasks.front());
|
||||
this->tasks.pop();
|
||||
}
|
||||
task();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
stop = true;
|
||||
}
|
||||
condition.notify_all();
|
||||
for (std::thread& worker : workers) {
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(std::function<void()> task) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
if (stop) {
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
}
|
||||
tasks.emplace(task);
|
||||
}
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
int main() {
|
||||
ThreadPool pool(4);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
pool.enqueue([i] {
|
||||
std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << '\n';
|
||||
});
|
||||
}
|
||||
return 0;
|
||||
}
|
24
program/c_cpp/linux/ncurses.c
Normal file
24
program/c_cpp/linux/ncurses.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <ncurses.h>
|
||||
|
||||
char fastRead();
|
||||
|
||||
int main() {
|
||||
char ch;
|
||||
printf("Please down any key\n");
|
||||
ch = fastRead();
|
||||
printf("down : %c --- %d\n", ch, (int)ch);
|
||||
return 0;
|
||||
}
|
||||
char fastRead() {
|
||||
char ch;
|
||||
filter(); // 阻止initscr 清空屏幕
|
||||
initscr(); // 初始化
|
||||
cbreak(); // 禁用缓冲区
|
||||
noecho(); // 禁用回显
|
||||
keypad(stdscr, TRUE);
|
||||
ch = getchar();
|
||||
refresh(); // 刷新
|
||||
endwin(); // 关闭
|
||||
return ch;
|
||||
}
|
25
program/c_cpp/linux/random.md
Normal file
25
program/c_cpp/linux/random.md
Normal file
@ -0,0 +1,25 @@
|
||||
# linux随机数设备
|
||||
从系统熵池进行获取
|
||||
|
||||
## index
|
||||
- [random-urandom](# random-urandom)
|
||||
- [note](# note)
|
||||
|
||||
## random-urandom
|
||||
/dev/random 和 /dev/urandom 的区别
|
||||
+ /dev/random:
|
||||
- 阻塞型设备,当熵池耗尽时会阻塞,直到收集到足够的熵
|
||||
- 适合生成高价值的密钥、证书等
|
||||
- 可能会影响性能,因为可能需要等待
|
||||
|
||||
+ /dev/urandom:
|
||||
- 非阻塞型设备,即使熵池耗尽也会继续提供数据
|
||||
- 使用加密算法从初始熵生成伪随机数
|
||||
- 对于大多数应用来说已经足够安全
|
||||
- 推荐在大多数情况下使用
|
||||
|
||||
## note
|
||||
- 对于大多数应用,使用 /dev/urandom 就足够了,它不会阻塞且性能更好
|
||||
- 只在生成长期加密密钥等极高安全需求时使用 /dev/random
|
||||
- 不要频繁打开和关闭设备文件,可以保持打开状态或重用文件描述符
|
||||
- 检查所有系统调用的返回值,确保操作成功
|
@ -1,19 +1,45 @@
|
||||
# 对象和类
|
||||
|
||||
## 访问控制
|
||||
```cpp
|
||||
## 目录
|
||||
- [访问控制](#访问控制)
|
||||
- [作用域运算符](#作用域运算符)
|
||||
- [类的六大特殊成员函数](#类的六大特殊成员函数)
|
||||
- [RAII](#RAII)
|
||||
- [move语义](#move)
|
||||
- [右值引用](#右值引用)
|
||||
- [初始化列表](#初始化列表)
|
||||
- [const 成员函数](#const成员函数)
|
||||
- [this指针](#this指针)
|
||||
- [作用域为类的常量](#作用域为类的常量)
|
||||
- [作用域内枚举](#作用域内枚举)
|
||||
- [友元](#友元)
|
||||
- [类的自动转换和强制类型转换](#类的自动转换和强制类型转换)
|
||||
- [转换函数](#转换函数)
|
||||
- [继承](#继承)
|
||||
- [继承方式](#继承方式)
|
||||
- [虚函数](#virtual)
|
||||
- [设计理念](#)
|
||||
- [is a](#)
|
||||
- [AbstactBaseClass](#ABC)
|
||||
|
||||
## 访问控制
|
||||
|
||||
```cpp
|
||||
class demo {
|
||||
public: // 公有接口
|
||||
public : // 公有接口
|
||||
private: // 私有成员
|
||||
protected: // 保护
|
||||
protected: // 保护,对外部是私有
|
||||
};
|
||||
```
|
||||
|
||||
## 作用域运算符(::)
|
||||
|
||||
可用于在类体外指出函数所属的类(命名空间)
|
||||
|
||||
## 成员函数的参数名不可与类成员相同
|
||||
**成员函数的参数名不可与类成员相同**
|
||||
|
||||
## 类的六大特殊成员函数(未定义时编译器提供默认版本)
|
||||
|
||||
```cpp
|
||||
demo::demo(); // 默认构造函数
|
||||
demo::~demo(); // 默认析构函数
|
||||
@ -23,7 +49,57 @@ demo::demo(demo&&); // 移动复制构造函数
|
||||
demo& demo::operator = (demo&&); // 移动赋值构造函数
|
||||
```
|
||||
|
||||
## const 成员函数 适合的成员函数要尽可能用,以帮助规避错误
|
||||
`demo::demo() = default;`显式声明为默认
|
||||
`demo::demo() = delete;`显式声明为禁用
|
||||
|
||||
|
||||
### RAII
|
||||
|
||||
在类的构造函数中申请堆内存,在析构函数中释放,这样可以保证类失效时内存被释放
|
||||
|
||||
### move
|
||||
|
||||
移动语义的核心思想是转移而非复制。当一个对象被移动时,其资源(如动态分配的内存、文件句柄等)被转移到目标对象,而源对象被置于一种有效但未定义的状态。这种状态通常是清空的,以确保源对象的资源在其生命周期内不会被重复释放
|
||||
|
||||
```cpp
|
||||
MyString(MyString&& other) noexcept : data(other.data) { // 移动构造函数
|
||||
other.data = nullptr;
|
||||
}
|
||||
MyString& operator=(MyString&& other) noexcept { // 移动赋值运算符
|
||||
if (this != &other) {
|
||||
delete[] data; // 释放当前对象的资源
|
||||
data = other.data;
|
||||
other.data = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
```
|
||||
|
||||
`std::move` 是一个函数模板,用于将左值强制转换为右值。它本身并不执行移动操作,而是通过返回一个右值引用,触发移动构造函数或移动赋值运算符
|
||||
|
||||
`MyString str2 = std::move(str1); // 触发移动构造函数`
|
||||
|
||||
#### 右值引用
|
||||
分为两类
|
||||
> 普通右值引用:直接声明的T&&,用于移动语义
|
||||
> 转发引用:模板函数中声明的T&&,用于完美转发
|
||||
|
||||
- [函数引用重载](./func#重载)
|
||||
|
||||
### 初始化列表
|
||||
|
||||
初始化列表是一种在构造函数中初始化类成员变量的机制
|
||||
|
||||
1. 初始化常量成员变量:常量成员变量必须在构造函数的初始化列表中初始化,不能在构造函数体内赋值。
|
||||
2. 初始化引用成员变量:引用成员变量必须在构造函数的初始化列表中初始化,不能在构造函数体内赋值。
|
||||
3. 调用基类的构造函数:如果类继承自基类,需要在初始化列表中显式调用基类的构造函数。
|
||||
4. 优化性能:对于一些复杂的成员变量(如类对象),使用初始化列表可以避免默认构造后再赋值,从而提高效率。
|
||||
|
||||
> example
|
||||
`MyClass(int a, int b, int c) : Base(a), myConst(b), myRef(c), myValue(10) {}`
|
||||
|
||||
## const成员函数 适合的成员函数要尽可能用,以帮助规避错误
|
||||
|
||||
`void show() const;` 声明
|
||||
`void demo::show() const;` 定义
|
||||
表明函数不会修改调用对象
|
||||
@ -70,3 +146,57 @@ operator typeName();
|
||||
+ 必须是类成员
|
||||
+ 不能有参数
|
||||
+ 不能指定返回类型
|
||||
|
||||
## 继承
|
||||
|
||||
基类对象需要在进入派生类的构造函数之前被创建,通常使用初始化列表解决
|
||||
`demo::demo() : base();`
|
||||
### 继承方式
|
||||
1. public
|
||||
+ 基类的公有成员在派生类中仍然是公有的。
|
||||
+ 基类的保护成员在派生类中仍然是保护的。
|
||||
+ 基类的私有成员在派生类中不可访问。
|
||||
+ 派生类*对象*可以访问基类的公有成员。
|
||||
+ 派生类*对象*不能直接访问基类的*私有成员*
|
||||
|
||||
2. protected
|
||||
+ 基类的公有成员和保护成员在派生类中都变成保护的。
|
||||
+ 基类的私有成员在派生类中仍然不可访问。
|
||||
+ 派生类*对象*不能直接访问基类的*所有成员*
|
||||
|
||||
3. private
|
||||
+ 基类所有成员变成私有
|
||||
+ 派生类*对象*不能直接访问基类的*所有成员*
|
||||
|
||||
__保护成员在派生类中的访问性__
|
||||
无论继承方式,派生类都可以访问基类的 `protected` 这是因为保护成员的设计初衷就是允许派生类访问,但不允许*派生类的对象*访问
|
||||
|
||||
### virtual
|
||||
虚函数是通过在基类中使用关键字 virtual 声明的成员函数
|
||||
|
||||
虚函数的主要作用是实现动态绑定或运行时多态.当通过基类指针或引用调用虚函数时,程序会根据对象的实际类型(运行时类型)来调用相应的函数版本
|
||||
|
||||
为了实现动态绑定,C++ 编译器会在每个具有虚函数的类的对象中隐式添加一个指针,指向一个虚函数表(V-Table)。V-Table 是一个函数指针数组,存储了类中所有虚函数的地址。当通过指针或引用调用虚函数时,程序会通过 V-Table 查找并调用正确的函数版本
|
||||
|
||||
**虚函数的特点**
|
||||
+ 必须是成员函数
|
||||
+ 派生类继承基类的虚函数,但可以重写它
|
||||
+ 覆盖:派生类中的虚函数与基类中的虚函数具有相同的签名
|
||||
+ 多态:通过基类指针或引用调用虚函数时,会根据对象的实际类型调用相应的函数版本
|
||||
|
||||
**纯虚函数与抽象类**
|
||||
如果一个虚函数在基类中没有实现,而是通过在函数声明后加上 = 0 来表示,那么这个函数称为纯虚函数。包含纯虚函数的类称为抽象类
|
||||
|
||||
`virtual void display() = 0; // 纯虚函数`
|
||||
|
||||
## 设计理念
|
||||
|
||||
### is-a
|
||||
### ABC
|
||||
即使用[纯虚函数](#virtual)构造的抽象类
|
||||
|
||||
无法构建对象,只能用于构造其他派生类
|
||||
|
||||
用于提取一系列对象的共性以共用
|
||||
|
||||
即抽象类设计理念,把一系列对象的共性提取出来,创建一个*抽象*的类
|
||||
|
42
program/c_cpp/universal/compile.md
Normal file
42
program/c_cpp/universal/compile.md
Normal file
@ -0,0 +1,42 @@
|
||||
# 预编译指令
|
||||
|
||||
## 目录
|
||||
- [define](#define)
|
||||
- [预定义宏](#预定义宏)
|
||||
- [ifdef](#ifdef)
|
||||
- [ifndef](#ifndef)
|
||||
- [endif](#endif)
|
||||
- [pragma](#pragma)
|
||||
- [error](#error)
|
||||
- [warning](#warning)
|
||||
|
||||
## define
|
||||
### 预定义宏
|
||||
1. 平台相关
|
||||
+ `__STDC__` 如果编译器遵循ANSI C标准,则定义为1
|
||||
+ `__cplusplus` 如果编译器支持C++,则定义为一个版本号 如199711L表示C++98,201103L表示C++11等
|
||||
+ `_WIN32` 在Windows平台下定义,表示目标系统是32位或64位
|
||||
+ `_WIN64`
|
||||
+ `__unix__`
|
||||
+ `__linux__`
|
||||
+ `__APPLE__`
|
||||
|
||||
2. 编译器相关
|
||||
+ `__GNUC__` 如果编译器是GCC,则定义为GCC的主版本号
|
||||
+ `__clang__` 如果编译器是Clang
|
||||
+ `_MSC_VER` 如果编译器是Microsoft Visual C++,则定义为一个版本号
|
||||
+ `__ICC` 如果编译器是Intel C/C++ Compiler,则定义
|
||||
|
||||
3. 文件和行号相关的预定义宏
|
||||
+ `__FILE__` 当前文件的名称
|
||||
+ `__LINE__` 当前文件的行号
|
||||
+ `__DATE__` 编译日期
|
||||
+ `__TIME__` 编译时间
|
||||
|
||||
4. 其他
|
||||
+ `__func__` `__FUNCTION__` 当前函数的名称
|
||||
+ `__PRETTY_FUNCTION__` 在C++中,包含当前函数的完整声明
|
||||
|
||||
## pragma
|
||||
|
||||
`#pragma once` 确保头文件只被包含一次
|
47
program/c_cpp/universal/func.md
Normal file
47
program/c_cpp/universal/func.md
Normal file
@ -0,0 +1,47 @@
|
||||
# c-cpp function
|
||||
|
||||
## 目录
|
||||
- [extern](#extern)
|
||||
- [noexcept](#noexcept)
|
||||
- [重载](#)
|
||||
- [often](#often)
|
||||
|
||||
## extern
|
||||
|
||||
`exterm` 表明函数在外部定义,在链接期才去查找
|
||||
`extern "C"` 表明以C的方式查找外部函数
|
||||
|
||||
## noexcept
|
||||
|
||||
```cpp
|
||||
void myFunction() noexcept {
|
||||
// 这个函数不会抛出异常
|
||||
}
|
||||
```
|
||||
noexcept 的一个重要用途是优化性能,特别是在移动语义中。当一个函数被标记为 noexcept 时,编译器可以更积极地优化代码
|
||||
|
||||
## 重载
|
||||
只要特征标不同就可以重载
|
||||
**特征标**:原型除去返回值都是
|
||||
|
||||
+ 左值:优先选择T&,如果不可用则选择const T&。
|
||||
+ const左值:选择const T&。
|
||||
+ 右值:优先选择T&&, else const T&
|
||||
+ 字面量或临时对象:选择T&&。
|
||||
|
||||
## often
|
||||
|
||||
```
|
||||
abs(x); //求x的绝对值 e.g.abs(-5)=5
|
||||
fabs() //实数绝对值
|
||||
exp(x); //求x的自然指数e^x e.g.exp(1)=2.718282
|
||||
floor(x); //向下取整
|
||||
ceil(x); //向上取整
|
||||
log(x); //求实数x的自然数对数 e.g.log(1)=0
|
||||
pow(x,y); //计算x^y,输出为双精度实数 e.g.pow(2,3)=8
|
||||
sqrt(x); //求x的平方根 e.g.sqrt(25)=5
|
||||
strlen(str);获取字符数组长度(只能用在字符数组)。
|
||||
max(a,b) //两数中最大
|
||||
min(a,b) //两数中最小
|
||||
swap(a,b) //交换两个类型相同的变量
|
||||
```
|
@ -6,6 +6,7 @@
|
||||
- [c fio](# c fio)
|
||||
- [cpp stdio](# cpp stdio)
|
||||
- [cpp fio](# cpp fio)
|
||||
- [关闭缓冲区读取](# ../linux/ncurses.c)
|
||||
|
||||
|
||||
## c stdio
|
||||
|
156
program/c_cpp/universal/ptr.md
Normal file
156
program/c_cpp/universal/ptr.md
Normal file
@ -0,0 +1,156 @@
|
||||
# c-cpp的指针问题
|
||||
|
||||
## 目录
|
||||
|
||||
- [NULL and nullptr](#NULL-nullptr)
|
||||
- [cpp智能指针](#cpp智能指针)
|
||||
- [注意事项](#注意事项)
|
||||
- [some example](#some-example)
|
||||
|
||||
## NULL-nullptr
|
||||
|
||||
在C和CPP中,NULL并不相同
|
||||
|
||||
```
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
```
|
||||
|
||||
由源码可知, C中 `NULL` 为 `(void *)0`, 而cpp中视为整形常量
|
||||
|
||||
因此cpp中应使用nullptr,否则函数重载中会出现选择错误问题
|
||||
|
||||
## cpp智能指针
|
||||
|
||||
1. `std::unique_ptr`
|
||||
|
||||
表示独占所有权的指针,即同一时刻只能有一个`unique_ptr`指向某个对象。
|
||||
|
||||
* 不可复制(没有拷贝构造函数和拷贝赋值运算符)。
|
||||
* 可以移动(支持移动语义)。
|
||||
* 自动释放资源。
|
||||
|
||||
**由于不可复制,不能将unique_ptr存储在标准容器中(如std::vector)**
|
||||
|
||||
```
|
||||
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(42); // 创建unique_ptr
|
||||
std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 移动所有权
|
||||
ptr1 = nullptr; // ptr1不再指向对象,对象由ptr2管理
|
||||
```
|
||||
|
||||
2. `std::shared_ptr`
|
||||
|
||||
表示共享所有权的指针,多个`shared_ptr`可以指向同一个对象
|
||||
|
||||
* 使用引用计数来管理对象的生命周期。
|
||||
* 当最后一个`shared_ptr`被销毁时,对象才会被释放。
|
||||
* 可以复制
|
||||
* 引用计数可能会引入性能开销,尤其是在多线程环境中。
|
||||
* 如果存在循环引用(如双向链表),可能导致内存泄漏。需要使用`std::weak_ptr`来解决。
|
||||
|
||||
```
|
||||
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42);
|
||||
std::shared_ptr<MyClass> ptr2 = ptr1; // 复制,引用计数加1
|
||||
std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl; // 输出2
|
||||
```
|
||||
|
||||
3. `std::weak_ptr`
|
||||
|
||||
解决`shared_ptr`的循环引用问题
|
||||
|
||||
* 不增加引用计数。
|
||||
* 可以通过lock()方法获取一个`shared_ptr`,但需要检查对象是否仍然存在
|
||||
* `weak_ptr`不能直接访问对象,需要通过lock()方法转换为`shared_ptr`。
|
||||
* 如果对象已经被销毁,lock()会返回一个空的`shared_ptr`
|
||||
|
||||
### 注意事项
|
||||
|
||||
***循环引用问题***
|
||||
|
||||
`std::shared_ptr`通过引用计数来管理对象的生命周期。当最后一个`shared_ptr`被销毁时,引用计数归零,对象才会被释放。然而,如果两个或多个`shared_ptr`相互引用,引用计数将永远不会归零,因为它们相互持有对方的引用。
|
||||
|
||||
> example:双向链表中的循环引用
|
||||
```
|
||||
struct Node {
|
||||
std::shared_ptr<Node> next; // 指向下一个节点
|
||||
std::shared_ptr<Node> prev; // 指向前一个节点
|
||||
};
|
||||
auto node1 = std::make_shared<Node>();
|
||||
auto node2 = std::make_shared<Node>();
|
||||
node1->next = node2; // node1 持有 node2 的共享所有权
|
||||
node2->prev = node1; // node2 持有 node1 的共享所有权
|
||||
```
|
||||
|
||||
为了解决循环引用问题,C++标准库提供了`std::weak_ptr`。`std::weak_ptr`是一种弱引用,它不会增加引用计数,但可以指向一个由`std::shared_ptr`管理的对象
|
||||
|
||||
```
|
||||
struct Node {
|
||||
std::shared_ptr<Node> next; // 指向下一个节点
|
||||
std::weak_ptr<Node> prev; // 使用 weak_ptr 指向前一个节点
|
||||
};
|
||||
auto node1 = std::make_shared<Node>();
|
||||
auto node2 = std::make_shared<Node>();
|
||||
node1->next = node2; // node1 持有 node2 的共享所有权
|
||||
node2->prev = node1; // node2 使用 weak_ptr 指向 node1
|
||||
```
|
||||
|
||||
如果对象仍然存在,lock()返回一个指向对象的`std::shared_ptr` 如果对象已经被销毁,lock()返回一个空的`std::shared_ptr`
|
||||
|
||||
|
||||
__正确选择智能指针类型__
|
||||
|
||||
> 如果对象的所有权是唯一的,使用`std::unique_ptr`
|
||||
> 如果对象的所有权需要共享,使用`std::shared_ptr`
|
||||
> 如果需要解决循环引用问题,使用`std::weak_ptr`
|
||||
|
||||
### some-example
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <algorithm> // 用于 std::fill
|
||||
int main() {
|
||||
// 使用 std::unique_ptr 管理1000个 int 的内存空间
|
||||
std::unique_ptr<int[]> data = std::make_unique<int[]>(1000);
|
||||
|
||||
// 初始化数据
|
||||
std::fill(data.get(), data.get() + 1000, 42); // 将所有元素初始化为42
|
||||
// data.get()返回底层指针,可以用于标准库算法(如std::fill)
|
||||
|
||||
// 访问并打印部分数据
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
std::cout << data[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// 当 unique_ptr 超出作用域时,内存会自动释放
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
```
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <algorithm> // 用于 std::fill
|
||||
int main() {
|
||||
// 使用 std::shared_ptr 管理1000个 int 的内存空间
|
||||
std::shared_ptr<int[]> data(new int[1000]); // 使用 new[] 分配内存
|
||||
// ***std::shared_ptr<int[]>需要显式使用new[]分配内存***
|
||||
|
||||
// 初始化数据
|
||||
std::fill(data.get(), data.get() + 1000, 42); // 将所有元素初始化为42
|
||||
|
||||
// 访问并打印部分数据
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
std::cout << data[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// 当最后一个 shared_ptr 超出作用域时,内存会自动释放
|
||||
return 0;
|
||||
}
|
||||
```
|
@ -1,12 +1,13 @@
|
||||
# 存储说明符
|
||||
+ static
|
||||
+ extern
|
||||
+ mutable
|
||||
+ thread_local
|
||||
# 说明符
|
||||
|
||||
# cv 说明符
|
||||
+ const
|
||||
+ volatile
|
||||
## 目录
|
||||
- [static](#static)
|
||||
- [extern](#extern):引用声明
|
||||
- [mutable](#mutable)
|
||||
- [thread local](#`thread_local`)
|
||||
- [const](#const)
|
||||
- [volatile](#volatile):强制读内存
|
||||
- [restrict](#restrict) : 指示编译器优化指针(C99)
|
||||
|
||||
|
||||
## static
|
||||
@ -18,7 +19,7 @@
|
||||
|
||||
## extern
|
||||
引用声明
|
||||
声明引用在其他地方定义的变量
|
||||
声明引用在其他地方定义的变量或者函数
|
||||
|
||||
## mutable
|
||||
即使结构(类)被声明为const,也可以被修改的成员函数
|
||||
@ -36,4 +37,15 @@
|
||||
就像使用了static
|
||||
如果希望连接性为外部,则可以用extern覆盖
|
||||
|
||||
## volatile 强制读内存
|
||||
## restrict
|
||||
- 在没有 restrict 的情况下,编译器需要考虑指针之间可能存在的别名关系。编译器会频繁地从内存中读取数据,以确保每次使用指针时数据是最新的。这会导致不必要的内存访问
|
||||
- 使用 restrict 后,编译器可以假设带有 restrict 的指针是唯一的,不会与其他指针指向同一块内存。因此,编译器可以减少不必要的内存访问
|
||||
|
||||
```c
|
||||
void copy(int *restrict dest, int *restrict src, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
```
|
||||
__如果违反了 restrict 的约束(即多个 restrict 指针指向同一块内存),程序的行为是未定义的__
|
||||
|
@ -1,35 +1,33 @@
|
||||
# 模板
|
||||
|
||||
## 目录
|
||||
- [函数模板](#)
|
||||
- [生成](#)
|
||||
- [类模板](#)
|
||||
- [完美转发](#)
|
||||
- [可变参数](#可变参数)
|
||||
|
||||
## 函数模板
|
||||
|
||||
### 基本格式
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
void swap(T &a, T &b) {
|
||||
T temp;
|
||||
temp = b;
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
void swap(T &a, T &b);
|
||||
```
|
||||
__函数模板必须放在头文件里,因为它不是函数实体,只能算编译指令__
|
||||
__函数模板必须放在编译器可见的地方里,因为不是函数实体,只能算编译指令__
|
||||
|
||||
### 模板的几个术语
|
||||
+ **隐式实例化**
|
||||
### 生成
|
||||
**隐式实例化**
|
||||
```cpp
|
||||
int a=0, b=3;
|
||||
swap<int>(a, b);
|
||||
```
|
||||
+ **显式实例化**
|
||||
**显式实例化**
|
||||
```cpp
|
||||
template void swap<int>(int&, int&); // 使用模板生成int类型的函数定义
|
||||
```
|
||||
+ **显式具体化**
|
||||
**显式具体化** 这个可以放到其他文件里,因为是有实体的
|
||||
```cpp
|
||||
template <> void swap<int>(int&, int&);
|
||||
```
|
||||
__这个可以放到其他文件里,因为是有实体的__
|
||||
|
||||
### 类型推导
|
||||
+ decltype()
|
||||
@ -39,5 +37,29 @@ decltype(a) var;
|
||||
```
|
||||
|
||||
## 类模板
|
||||
同样没有实体,包括类成员方法等都要写成模板的格式
|
||||
|
||||
+ 同样没有实体,包括类成员方法等都要写成模板的格式
|
||||
## 完美转发
|
||||
- [右值引用](./class.md#):有关完美转发的基础
|
||||
完美转发允许模板函数将参数原封不动地转发给另一个函数,保留其左值或右值的性质。这在编写通用代码时非常有用,例如模板库或函数包装器
|
||||
|
||||
完美转发的核心是std::forward,它根据模板参数T的类型(左值引用或右值引用)来决定如何转发参数
|
||||
|
||||
```
|
||||
template <typename T>
|
||||
void wrapper(T&& arg) {
|
||||
// 转发 arg 到另一个函数,保留其左值或右值性质
|
||||
targetFunction(std::forward<T>(arg));
|
||||
}
|
||||
```
|
||||
|
||||
## 可变参数
|
||||
|
||||
```
|
||||
void print() {} // 终止递归
|
||||
template <typename T, typename... Types)
|
||||
void print(const T& firstArg, const Types&... args) {
|
||||
std::cout << firstArg << std::endl;
|
||||
print(args...);
|
||||
}
|
||||
```
|
||||
|
@ -1,35 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
void func(int a) {
|
||||
cout << a << endl;
|
||||
}
|
||||
|
||||
mutex mtx; // 互斥量
|
||||
|
||||
int main() {
|
||||
|
||||
// 同一个进程的多个线程共享该进程的全部系统资源
|
||||
// 但各个线程有自己的调用栈,寄存器,本地存储
|
||||
|
||||
// thread类
|
||||
// 1.
|
||||
// thread() noexcept;默认构造函数,不执行任何任务
|
||||
// 2.
|
||||
// template<class Funtion, class ...Args>
|
||||
// explicit thread(Function&& fx,Args&&... args);
|
||||
|
||||
thread t1(func, 1); //用2方法创建线程
|
||||
|
||||
// mtx.lock();
|
||||
// mtx.unlock();
|
||||
|
||||
|
||||
if(t1.joinable()) // 判断能否调用join
|
||||
t1.join(); //回收线程t1
|
||||
// t1.detach(); //分离线程
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 注:g++编译器要加 -pthread -std=c++11选项编译
|
130
program/c_cpp/universal/thread.md
Normal file
130
program/c_cpp/universal/thread.md
Normal file
@ -0,0 +1,130 @@
|
||||
# cpp多线程
|
||||
C++11引入了标准的线程库 `<thread>`,使得多线程编程更加方便和标准化
|
||||
|
||||
## 目录
|
||||
- [创建线程](#)
|
||||
- [线程的分离和结合](#)
|
||||
- [传递参数给线程函数](#)
|
||||
- [线程的同步](#)
|
||||
- [互斥锁](#mutex)
|
||||
- [lock-guard](#)
|
||||
- [条件变量](#)
|
||||
- [原子操作](#atomic)
|
||||
- [高级接口](#高级接口)
|
||||
- [线程池](#)
|
||||
|
||||
## 创建线程
|
||||
通过 `std::thread` 类来创建和管理线程
|
||||
```
|
||||
std::thread t(thread_function); // 创建线程并执行 thread_function
|
||||
t.join(); // 等待线程结束
|
||||
```
|
||||
|
||||
## 线程的分离和结合
|
||||
+ `join()`:主线程等待子线程执行完毕。
|
||||
+ `detach()`:将子线程与主线程分离,子线程在后台独立运行。
|
||||
|
||||
## 传递参数给线程函数
|
||||
可以通过 `std::thread` 的构造函数传递参数给线程函数
|
||||
|
||||
`std::thread t(thread_function, 10, "Hello");`
|
||||
|
||||
## 线程的同步
|
||||
多个线程访问共享资源时,可能会出现竞争条件(Race Condition)。为了避免这种情况,可以使用互斥锁(Mutex)来同步线程
|
||||
|
||||
### 互斥锁
|
||||
`std::mutex` 用于保护共享资源,确保同一时间只有一个线程可以访问,`<mutex>`
|
||||
|
||||
```
|
||||
std::mutex mtx; // 互斥量
|
||||
void print_block() {
|
||||
mtx.lock(); // 锁定互斥锁
|
||||
// ...
|
||||
mtx.unlock(); // 解锁互斥锁
|
||||
}
|
||||
// in main ->
|
||||
std::thread t1(print_block, 50, '*');
|
||||
std::thread t2(print_block, 50, '$');
|
||||
t1.join();
|
||||
t2.join();
|
||||
```
|
||||
|
||||
### lock-guard
|
||||
`std::lock_guard` 是一个 RAII 风格的互斥锁管理类,它在构造时锁定互斥锁,在析构时自动解锁0
|
||||
|
||||
```
|
||||
std::mutex mtx;
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
```
|
||||
|
||||
## 条件变量
|
||||
条件变量用于线程间的同步,允许线程在某些条件不满足时等待,直到其他线程通知条件满足
|
||||
|
||||
`<condition_variable>`
|
||||
```cpp
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
bool ready = false;
|
||||
void print_id(int id) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
while (!ready) {
|
||||
cv.wait(lock); // 线程等待条件变量
|
||||
}
|
||||
std::cout << "thread " << id << '\n';
|
||||
}
|
||||
void go() {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
ready = true;
|
||||
cv.notify_all(); // 通知所有等待的线程
|
||||
}
|
||||
// main
|
||||
std::thread threads[10];
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
threads[i] = std::thread(print_id, i);
|
||||
}
|
||||
go();
|
||||
for (auto& th : threads) {
|
||||
th.join();
|
||||
}
|
||||
```
|
||||
|
||||
## atomic
|
||||
`std::atomic` 提供了原子操作,确保对共享变量的操作是不可分割的
|
||||
|
||||
## 高级接口
|
||||
|
||||
```cpp
|
||||
void wait_s(time_t sec) { // 延时函数
|
||||
std::cout << "BEGIN" << std::endl;
|
||||
time_t begin = time(0);
|
||||
while((time(0) - begin) < sec);
|
||||
}
|
||||
int main() {
|
||||
std::future<void> r1(std::async(wait_s, 10));
|
||||
// async let `a piece of functionality` run in alone thread
|
||||
|
||||
wait_s(10);
|
||||
r1.get(); // 获得返回值,确保必将被调用
|
||||
|
||||
std::cout << "END" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 线程池
|
||||
通过 `std::thread` 和任务队列来实现一个简单的[线程池](../library/thread-pool.cpp)
|
||||
|
||||
// thread类
|
||||
// 1.
|
||||
// thread() noexcept;默认构造函数,不执行任何任务
|
||||
// 2.
|
||||
// template<class Funtion, class ...Args>
|
||||
// explicit thread(Function&& fx,Args&&... args);
|
||||
|
||||
if(t1.joinable()) // 判断能否调用join
|
||||
t1.join(); //回收线程t1
|
||||
// t1.detach(); //分离线程
|
||||
return 0;
|
||||
}
|
||||
|
||||
__注:g++编译器要加 -pthread -std=c++11选项编译__
|
@ -1,34 +0,0 @@
|
||||
abs(x); //求x的绝对值 e.g.abs(-5)=5
|
||||
fabs() //实数绝对值
|
||||
a=clock();测量从程序开始到目前的时间,并把值给a。(单位毫秒级)
|
||||
exp(x); //求x的自然指数e^x e.g.exp(1)=2.718282
|
||||
floor(x); //向下取整
|
||||
ceil(x); //向上取整
|
||||
log(x); //求实数x的自然数对数 e.g.log(1)=0
|
||||
pow(x,y); //计算x^y,输出为双精度实数 e.g.pow(2,3)=8
|
||||
sqrt(x); //求x的平方根 e.g.sqrt(25)=5
|
||||
str.length();获取字符串长度(只能用在字符串)string b="123456789";//字符串定义 初始化。
|
||||
str.size();
|
||||
strlen(str);获取字符数组长度(只能用在字符数组)。
|
||||
abort() //终止程序运行 不能结束工作
|
||||
exit() //终止程序运行 做结束工作
|
||||
max(a,b) //两数中最大
|
||||
min(a,b) //两数中最小
|
||||
swap(a,b) //交换两个类型相同的变量
|
||||
|
||||
sort(数组名+起始单元,数组名+结束单元,排序方法cmp倒);
|
||||
sort(a,a+n);//sort默认为升序
|
||||
int cmp(int a,int b)
|
||||
{
|
||||
return a>b;
|
||||
}
|
||||
|
||||
Sleep(s时间);//程序运行到此处时暂停s毫秒,注意大小写,需调用头文件#include<windows.h>
|
||||
|
||||
void color(const unsigned short textColor) //颜色字函数
|
||||
{
|
||||
if(textColor>=0&&textColor<=15)
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),textColor);
|
||||
else
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
a1 = int(input("input:")) # input
|
||||
print('%8d'%a1, '\n') # print
|
||||
# print(objects, sep=' ', wnd='\n')
|
||||
a1 = int(input("input:")) # input
|
||||
a, b = map(int, input().split()) # 读取输入分割并转化
|
||||
print('%8d'%a1, '\n') # print
|
||||
# print(objects, sep=' ', end='\n')
|
||||
|
||||
|
||||
# 数据类型
|
||||
@ -18,38 +19,38 @@ print()
|
||||
|
||||
# 运算符
|
||||
"""
|
||||
1. **
|
||||
2. * / % //
|
||||
3. + -
|
||||
4. <= < > >=
|
||||
5. <> == !=
|
||||
6. = %= /= //= -= += *= **=
|
||||
7. not or and
|
||||
1. **
|
||||
2. * / % //
|
||||
3. + -
|
||||
4. <= < > >=
|
||||
5. <> == !=
|
||||
6. = %= /= //= -= += *= **=
|
||||
7. not or and
|
||||
"""
|
||||
|
||||
# 条件判断
|
||||
if (x1==a1) and (x3==True):
|
||||
print("OK!!!")
|
||||
print("OK!!!")
|
||||
elif x3==False:
|
||||
print("x3==False")
|
||||
print("x3==False")
|
||||
else:
|
||||
print("x1:", x1)
|
||||
print("a1:", a1)
|
||||
print("x1:", x1)
|
||||
print("a1:", a1)
|
||||
print()
|
||||
|
||||
|
||||
# 循环控制
|
||||
for i in range(10): # 逐一访问序列中的元素
|
||||
while i>=9 and i<13: # 通过条件控制
|
||||
print(i)
|
||||
i+=1
|
||||
continue
|
||||
break
|
||||
for i in range(10): # 逐一访问序列中的元素
|
||||
while i>=9 and i<13: # 通过条件控制
|
||||
print(i)
|
||||
i+=1
|
||||
continue
|
||||
break
|
||||
|
||||
# range() 函数 创建一个整数列表
|
||||
# range() 函数 创建一个整数列表
|
||||
"""
|
||||
# 基本格式
|
||||
range(start, stop,[step])
|
||||
# 开始 结束 步长
|
||||
range(5, 1, -1) # 可做到倒序输出
|
||||
# 基本格式
|
||||
range(start, stop,[step])
|
||||
# 开始 结束 步长
|
||||
range(5, 1, -1) # 可做到倒序输出
|
||||
"""
|
||||
|
@ -1,23 +0,0 @@
|
||||
# 字符串
|
||||
s = str("Hello world")
|
||||
|
||||
print(s[3])
|
||||
print(s[-3])
|
||||
print(s[0:3]) # 字符串切片
|
||||
print(s[3:])
|
||||
print(s[:5])
|
||||
print(s[:-5])
|
||||
print(s[::-1]) # 倒序
|
||||
len(s) # 计算长度
|
||||
|
||||
# 字符串查询
|
||||
s.find('w')
|
||||
s.count('l')
|
||||
|
||||
s.replace('H','h') # H变成h
|
||||
s.casefold() # 大写转小写
|
||||
s.upper() # 小写转大写
|
||||
s.swapcase() # 转换大小写
|
||||
eval('12+3') # 计算值 返回15
|
||||
|
||||
|
97
program/python/basics/summary.md
Normal file
97
program/python/basics/summary.md
Normal file
@ -0,0 +1,97 @@
|
||||
# python基础合集
|
||||
|
||||
## 目录
|
||||
|
||||
- [程序之始](#run)
|
||||
- [IO](#IO)
|
||||
- [格式化输出](#)
|
||||
- [字符串](#string)
|
||||
- [DEBUG](#Debug)
|
||||
- [变量](#)
|
||||
- [数值类型](#)
|
||||
|
||||
## run
|
||||
|
||||
`if __name__ == '__main__'` 判断程序是否在主函数内(区别与模块等)
|
||||
|
||||
## IO
|
||||
|
||||
`print(values, sep, end)` 值, 分割符, 结尾符
|
||||
> `print("hello", sep=',', end='_')`
|
||||
> `print('%8d'%a1, '\n')`
|
||||
|
||||
a1 = int(input("input:")) # input
|
||||
a, b = map(int, input().split()) # 读取输入分割并转化
|
||||
|
||||
### 格式化输出
|
||||
1. 占位符
|
||||
+ `%`
|
||||
+ `format()`
|
||||
+ `格式化f`
|
||||
|
||||
> example
|
||||
`print("%4d" % a)`
|
||||
|
||||
|
||||
## string
|
||||
|
||||
字符串可以用单引号或者双引号
|
||||
|
||||
三引号可以跨行
|
||||
|
||||
> example
|
||||
```python
|
||||
print('''Hello
|
||||
world''')
|
||||
```
|
||||
|
||||
```
|
||||
s = str("Hello world")
|
||||
print(s[3])
|
||||
print(s[-3])
|
||||
print(s[0:3]) # 字符串切片
|
||||
print(s[3:])
|
||||
print(s[:5])
|
||||
print(s[:-5])
|
||||
print(s[::-1]) # 倒序
|
||||
len(s) # 计算长度
|
||||
|
||||
s.find('w')
|
||||
s.count('l')
|
||||
|
||||
s.replace('H','h') # H变成h
|
||||
s.casefold() # 大写转小写
|
||||
s.upper() # 小写转大写
|
||||
s.swapcase() # 转换大小写
|
||||
eval('12+3') # 计算值 返回15
|
||||
```
|
||||
|
||||
## Debug
|
||||
|
||||
1. pdb
|
||||
`import pdb; pdb.set_trace()` 程序运行到这行代码时会进入调试模式
|
||||
+ n(next):执行下一行代码。
|
||||
+ c(continue):继续运行直到遇到下一个断点。
|
||||
+ q(quit):退出调试。
|
||||
+ p <变量>:打印变量的值。
|
||||
+ l(list):显示当前代码上下文。
|
||||
+ b <行号>:设置断点。
|
||||
+ cl(clear):清除断点。
|
||||
```
|
||||
def add(a, b):
|
||||
import pdb; pdb.set_trace() # 从这里进入断点调试
|
||||
return a + b
|
||||
print(add(3,5))
|
||||
```
|
||||
|
||||
## 变量
|
||||
name = value
|
||||
|
||||
### 数值类型
|
||||
+ int
|
||||
+ float
|
||||
+ bool True = 1 False = 0
|
||||
+ complex
|
||||
+ [str](#string)
|
||||
|
||||
type()
|
@ -1,8 +1,39 @@
|
||||
安装docker
|
||||
sudo apt-get install docker-compose
|
||||
# docker
|
||||
是一个开源的应用容器引擎
|
||||
|
||||
配置/etc/docker/daemon.json
|
||||
|
||||
## 目录
|
||||
- [核心组件](#)
|
||||
- [install](#)
|
||||
- [基本命令](#)
|
||||
- [样例](#example-command)
|
||||
- [数据管理](#)
|
||||
- [高级用法](#)
|
||||
- [daemon.json](#)
|
||||
|
||||
## 核心组件
|
||||
+ 镜像(Image):只读模板,包含运行应用所需的所有内容,如代码、运行时、库等
|
||||
+ 容器(Container):镜像的运行实例,隔离运行应用的环境
|
||||
+ 仓库(Repository):存储和分发镜像的地方,Docker Hub 是最常用的公共仓库
|
||||
|
||||
|
||||
## install
|
||||
+ 更新系统并安装依赖包
|
||||
+ 添加 Docker 官方 GPG 密钥并设置存储库
|
||||
+ 安装 Docker 引擎并启动服务
|
||||
+ 设置 Docker 开机自启
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
|
||||
echo "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list.d/docker.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install docker-ce docker-ce-cli containerd.io
|
||||
# 验证安装
|
||||
sudo docker --version
|
||||
```
|
||||
|
||||
__配置/etc/docker/daemon.json__
|
||||
```
|
||||
{
|
||||
"registry-mirrors":
|
||||
[
|
||||
@ -11,23 +42,173 @@
|
||||
"https://docker.nju.edu.cn"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
docker ps #查看所有运行容器
|
||||
docker ps -a #全部
|
||||
## 基本命令
|
||||
1. 镜像操作
|
||||
+ `docker pull <镜像名>` : 从仓库拉取镜像
|
||||
+ `docker image ls` : 列出本地镜像
|
||||
+ `docker rmi <镜像ID>` : 删除镜像
|
||||
|
||||
docker stop [ID / NAME] #停止某容器
|
||||
2. 容器操作
|
||||
+ `docker run -d <镜像名>` : 创建并后台运行容器
|
||||
+ `docker ps` : 列出所有运行中容器
|
||||
+ `docker stop [ID / NAME]` : 停止某容器
|
||||
+ `docker start [ID / NAME]` : 启动已经停止的容器
|
||||
+ `docker rm [ID / NAME]` : 删除容器
|
||||
+ `docker commit <容器ID或名称> <新镜像名称>:<标签>` 将运行中的容器保存为镜像
|
||||
+ `docker save -o my-new-image.tar my-new-image:latest` 导出为tar文件
|
||||
+ `docker load -i my-new-image.tar` 导入镜像到目标环境
|
||||
|
||||
docker start [ID / NAME] #启动和删除容器
|
||||
docker rm [ID / NAME]
|
||||
3. 其他
|
||||
+ `docker search <镜像名>` 搜索镜像
|
||||
+ `docker logs <容器ID>` : 查看容器日志
|
||||
+ `docker exec -it [ID / NAME] /bin/bash` : 进入容器
|
||||
+ `c-P c-Q` : 退出容器
|
||||
+ `sudo systemctl daemon-reload && sudo systemctl restart docker` 重启
|
||||
+ `docker load < xxx.tar` #导入tar为镜像
|
||||
+ `docker commit [ID] [镜像名]` #容器保存为镜像
|
||||
|
||||
docker pull 仓库名/镜像名
|
||||
### example-command
|
||||
> `docker pull ubuntu` 拉取 Ubuntu 镜像
|
||||
> `docker run -it ubuntu /bin/bash` 运行 Ubuntu 容器并进入交互式 shell
|
||||
> `docker ps -a` 列出所有容器(包括停止的)
|
||||
> `docker run -it --name mc-ser ubuntu -v /opt/mc:/opt/mc -p 25565:25565 /bin/bash`
|
||||
|
||||
docker save [ID] > xxx.tar #导出为tar文件
|
||||
docker load < xxx.tar #导入tar为镜像
|
||||
## 数据管理
|
||||
为了持久化数据,Docker 提供了多种数据管理方式,主要包括 数据卷(Volumes)、绑定挂载(Bind Mounts) 和 临时文件系统(tmpfs)
|
||||
|
||||
docker commit [ID] [镜像名] #容器保存为镜像
|
||||
1. Docker 数据卷(Volumes)
|
||||
数据卷是 Docker 推荐的数据持久化方式。数据卷存储在 Docker 管理的文件系统中(通常是 /var/lib/docker/volumes/),与容器的生命周期分离,即使容器被删除,数据卷仍然存在
|
||||
|
||||
docker image ls #查看本地所有镜像
|
||||
docker rmi [ID / NAME] #删除镜像
|
||||
+ 持久化:数据卷独立于容器,容器删除后数据仍然保留。
|
||||
+ 高性能:数据卷通常比绑定挂载性能更好。
|
||||
+ 易于备份和迁移:数据卷可以通过 Docker 命令轻松备份和恢复。
|
||||
|
||||
docker exec -it [ID / NAME] bash #操作容器
|
||||
> `docker volume create my_volume` 创建数据卷
|
||||
> `docker volume ls` 查看数据卷
|
||||
> `docker volume inspect my_volume` 查看数据卷详细信息
|
||||
> `docker run -d --name my_container -v my_volume:/path/in/container <image_name>` 挂载数据卷到容器
|
||||
> `docker volume rm my_volume` 删除数据卷
|
||||
> `docker volume prune` 清理未使用的数据卷
|
||||
|
||||
2. 绑定挂载(Bind Mounts)
|
||||
绑定挂载是将主机上的文件或目录直接挂载到容器中
|
||||
|
||||
+ 灵活性:可以直接挂载主机上的任意文件或目录。
|
||||
+ 实时同步:主机和容器之间的文件修改会实时同步。
|
||||
+ 依赖主机文件系统:绑定挂载的路径必须存在于主机上。
|
||||
|
||||
- `docker run -d --name my_container -v /host/path:/container/path <image_name>` 挂载主机目录到容器
|
||||
|
||||
3. 临时文件系统(tmpfs)
|
||||
tmpfs 是一种基于内存的文件系统,适用于需要临时存储数据的场景。数据仅存储在内存中,容器停止后数据会丢失
|
||||
|
||||
+ 高性能:数据存储在内存中,读写速度快。
|
||||
+ 临时性:数据不会持久化,容器停止后数据丢失。
|
||||
|
||||
`docker run -d --name my_container --tmpfs /container/path <image_name>` 挂载 tmpfs 到容器
|
||||
|
||||
4. 数据卷的高级用法
|
||||
多个容器可以共享同一个数据卷,实现数据共享
|
||||
```
|
||||
docker run -d --name container1 -v my_volume:/data <image_name>
|
||||
docker run -d --name container2 -v my_volume:/data <image_name>
|
||||
```
|
||||
|
||||
可以将数据卷或绑定挂载设置为只读,防止容器修改数据
|
||||
`docker run -d --name my_container -v my_volume:/data:ro <image_name>`
|
||||
|
||||
## 高级用法
|
||||
1. Dockerfile
|
||||
Dockerfile 是用于构建镜像的脚本文件,包含一系列指令,用于定义镜像的构建过程
|
||||
```
|
||||
# 使用基础镜像
|
||||
FROM ubuntu:latest
|
||||
|
||||
# 维护者信息
|
||||
MAINTAINER Your Name <your.email@example.com>
|
||||
|
||||
# 更新包索引并安装软件
|
||||
RUN apt-get update && apt-get install -y \
|
||||
software-properties-common \
|
||||
python3
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制当前目录下的文件到容器中的 /app 目录
|
||||
COPY . /app
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 设置环境变量
|
||||
ENV NAME World
|
||||
|
||||
# 运行命令
|
||||
CMD ["python3", "app.py"]
|
||||
```
|
||||
`docker build -t <image_name> .` 构建镜像
|
||||
|
||||
2. Docker 网络
|
||||
`docker network create <network_name>` 创建网络
|
||||
|
||||
`docker network ls` 查看网络
|
||||
|
||||
`docker network connect <network_name> <container_id>` 连接容器到网络
|
||||
|
||||
3. Docker 数据管理
|
||||
`docker volume create <volume_name>` 创建数据卷
|
||||
|
||||
`docker volume ls` 查看数据卷
|
||||
|
||||
`docker run -v <volume_name>:/path/in/container <image_name>` 挂载数据卷到容器
|
||||
|
||||
4. Docker 资源限制
|
||||
`docker run -m 512m <image_name>` 限制内存
|
||||
|
||||
`docker run --cpus="1.5" <image_name>` 限制 CPU
|
||||
|
||||
5. Docker 安全
|
||||
> 使用非 root 用户运行容器
|
||||
```dockerfile
|
||||
FROM ubuntu
|
||||
RUN useradd -m myuser
|
||||
USER myuser
|
||||
```
|
||||
> 限制容器权限
|
||||
`docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE <image_name>`
|
||||
|
||||
## daemon.json
|
||||
```
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://docker.1ms.run",
|
||||
"https://docker.xuanyuan.me",
|
||||
"https://docker.zhai.cm",
|
||||
"https://a.ussh.net",
|
||||
"https://hub.littlediary.cn",
|
||||
"https://hub.rat.dev",
|
||||
"https://atomhub.openatom.cn",
|
||||
"https://docker.m.daocloud.io",
|
||||
"https://dytt.online",
|
||||
"https://func.ink",
|
||||
"https://lispy.org",
|
||||
"https://docker.xiaogenban1993.com",
|
||||
"https://docker.mybacc.com",
|
||||
"https://docker.yomansunter.com",
|
||||
"https://dockerhub.websoft9.com",
|
||||
"https://docker-0.unsee.tech",
|
||||
"https://docker-cf.registry.cyou",
|
||||
"https://docker.1panel.live",
|
||||
"https://docker.imgdb.de",
|
||||
"https://docker.hlmirror.com",
|
||||
"https://dockerpull.org",
|
||||
"https://dockerhub.icu",
|
||||
"https://proxy.1panel.live",
|
||||
"https://docker.1panel.top",
|
||||
"https://docker.ketches.cn"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
@ -1,29 +0,0 @@
|
||||
g++ -S test.s test.cpp #编译成汇编文件
|
||||
g++ -c test.o test.s #目标文件
|
||||
g++ -o test test.o #链接
|
||||
|
||||
g++ -O1/-O2/-O3 // 优化选项
|
||||
|
||||
g++ -S -o - -fverbose-asm xxx.cpp > xxx.s // 输出带注释的汇编
|
||||
|
||||
|
||||
#静态库制作:
|
||||
g++ -c -o libtest.a {test.cpp 源代码文件清单}
|
||||
// g++ -c test.cpp
|
||||
// ar -crv libtest.a test.o
|
||||
|
||||
|
||||
#动态库制作
|
||||
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 -ltest -L/home/e0x1a/test
|
||||
|
||||
如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查
|
||||
用 echo $LD_LIBRARY_PATH 查看
|
43
program/tool/gcc_g++.md
Normal file
43
program/tool/gcc_g++.md
Normal file
@ -0,0 +1,43 @@
|
||||
# gcc-g++ 编译器
|
||||
|
||||
## 目录
|
||||
- [编译选项](#编译选项)
|
||||
- [制作库文件](#制作库文件)
|
||||
|
||||
## 编译选项
|
||||
`g++ -S test.s test.cpp` 编译成汇编文件
|
||||
`g++ -c test.o test.s` 目标文件
|
||||
`g++ -o test test.o` 链接
|
||||
|
||||
`g++ -O1/-O2/-O3` // 优化选项
|
||||
|
||||
`g++ -S -o - -fverbose-asm xxx.cpp > xxx.s` // 输出带注释的汇编
|
||||
|
||||
`gcc -s` 选项用于剥除可执行文件中的符号表和重定位信息,减小可执行文件的大小
|
||||
- **正常功能保持**
|
||||
- **性能无显著差异**
|
||||
- **调试困难**:符号表中包含了函数名、变量名等调试信息。使用 `-s` 选项后,这些信息会被移除,使得调试变得非常困难
|
||||
- **反汇编和分析不便**:没有符号表,反汇编工具(如 `objdump`)无法显示函数名和变量名等信息,只能显示汇编指令和地址。这会增加对程序进行反汇编分析的难度。
|
||||
|
||||
|
||||
## 制作库文件
|
||||
> 静态库制作:
|
||||
g++ -c -o libtest.a {test.cpp 源代码文件清单}
|
||||
// g++ -c test.cpp
|
||||
// ar -crv libtest.a test.o
|
||||
|
||||
|
||||
> 动态库制作
|
||||
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 -ltest -L/home/e0x1a/test
|
||||
|
||||
如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查
|
||||
用 echo $LD_LIBRARY_PATH 查看
|
63
program/tool/gdb.md
Normal file
63
program/tool/gdb.md
Normal file
@ -0,0 +1,63 @@
|
||||
# gdb c/c++ 代码调试工具
|
||||
使用 -g 生成调试文件,不可以加 -O 选项
|
||||
|
||||
## 目录
|
||||
- [基础使用](#基础使用)
|
||||
- [run](#run)
|
||||
- [set](#set)
|
||||
- [mem](#mem)
|
||||
- [disassemble](#disassemble)
|
||||
- [info](#info)
|
||||
- [core](#core)
|
||||
|
||||
## 基础使用
|
||||
`l n` 列出源码
|
||||
`b n` 在第n行打断点
|
||||
`break main if var_name > 10` 满足条件时打断点
|
||||
`d n` 删除断点
|
||||
`lay next` 切换窗口布局TUI
|
||||
`Ctrl-x a` 退出TUI
|
||||
`Ctrl-x 1` 恢复单窗口布局
|
||||
`Ctrl-x o` 切换窗口焦点
|
||||
`ref``Ctrl-L` 刷新布局
|
||||
|
||||
### run
|
||||
`r` 开始运行到第一个断点
|
||||
`c` 继续运行到下一个断点
|
||||
`s` 步入
|
||||
`si` 单步汇编
|
||||
`n` 步过
|
||||
`ni`
|
||||
`q` 退出
|
||||
|
||||
### set
|
||||
`set [argc]` 传入参数
|
||||
`set var []` # 修改变量的值
|
||||
`set $rsp = 0x7ccc` # 修改寄存器的值
|
||||
|
||||
### mem
|
||||
`p` # 查看特定变量或表达式的值
|
||||
`bt` # 查看函数调用栈
|
||||
`bt full` # 详细信息
|
||||
`x/10gx $rsp` # 查看内存中由$rsp开始的10个八字节数据 g:八字节 x:16进制
|
||||
|
||||
### disassemble
|
||||
`disassemble` # 查看当前函数的汇编,可在后面加函数名看指定汇编
|
||||
`x/i $pc` # 检查pc处的汇编
|
||||
|
||||
### info
|
||||
`info locals` # 查看局部变量
|
||||
`info registers` # 查看寄存器状态
|
||||
`info program` # 查看程序运行信息
|
||||
`info break` # 查看断点信息
|
||||
`info threads` # 查看所有线程
|
||||
|
||||
## core
|
||||
1. `ulimit -c unlimited` 使挂掉的程序产生core文件
|
||||
|
||||
2. 修改 `/proc/sys/kernel/core_pattern` 使其在当前目录下生成core文件
|
||||
> `sudo echo "./core" > /proc/sys/kernel/core_pattern
|
||||
|
||||
3. gdb ./a.out core
|
||||
|
||||
gdb demo -p [pid] # 调试运行中的程序
|
@ -1,35 +0,0 @@
|
||||
gdb c/c++ 代码调试工具
|
||||
使用 g++ -g 生成调试文件,不可以加 -O 选项
|
||||
|
||||
set [argc] # 传入参数
|
||||
l n # 列出源码
|
||||
r # 开始运行到第一个断点
|
||||
b n # 在第n行打断点
|
||||
break main if var_name > 10 # 满足条件时打断点
|
||||
d n # 删除断点
|
||||
c # 继续运行到下一个断点
|
||||
s # 单步执行
|
||||
si # 单步汇编
|
||||
n # 单步执行,不进入函数
|
||||
q # 退出
|
||||
|
||||
set var [] # 修改变量的值
|
||||
set $rsp = 0x7ccccccc # 修改寄存器的值
|
||||
|
||||
p # 查看特定变量或表达式的值
|
||||
bt # 查看函数调用栈
|
||||
bt full # 详细信息
|
||||
disassemble # 查看当前函数的汇编,可在后面加函数名看指定汇编
|
||||
x/10gx $rsp # 查看内存中由$rsp开始的10个八字节数据 g:八字节 x:16进制
|
||||
|
||||
info locals # 查看局部变量
|
||||
info registers # 查看寄存器状态
|
||||
info program # 查看程序运行信息
|
||||
info break # 查看断点信息
|
||||
info threads # 查看所有线程
|
||||
|
||||
使用gdb调试core文件
|
||||
使用ulimit -c unlimited 使挂掉的程序产生core文件
|
||||
gdb ./a.out core
|
||||
|
||||
gdb demo -p [pid] # 调试运行中的程序
|
@ -1,46 +1,486 @@
|
||||
# makefile
|
||||
# make
|
||||
|
||||
makefile 是一个通用的项目代码构建器
|
||||
由规则 依赖 命令构成
|
||||
## 目录
|
||||
- [参数](#参数)
|
||||
- [makefile](#makefile)
|
||||
|
||||
## 参数
|
||||
`-n` 参数可以打印出make会执行的命令,但不真正执行
|
||||
`-f <filename>` 指定makefile
|
||||
`-i` 忽略错误
|
||||
`-k` 在某个目标失败时,尽量构建其他
|
||||
`-s` 静默
|
||||
`-j4` 4线程
|
||||
`-C /dir` 进入指定目录再运行
|
||||
`-d` debug
|
||||
`-w` 打印工作目录
|
||||
`-B` 强制重新构建
|
||||
|
||||
## makefile
|
||||
Makefile 是一种用于自动化构建和管理项目的工具,尤其在 C/C++ 项目中广泛使用。除了基本的规则和依赖关系,Makefile 还支持一些高级语法和功能,可以帮助你编写更灵活和高效的构建脚本
|
||||
|
||||
规则:依赖
|
||||
命令
|
||||
__注意: 命令前面必须要用Tab__
|
||||
|
||||
+ -n 参数可以打印出make会执行的命令,但不真正执行
|
||||
|
||||
# 注意: 命令前面必须要用Tab
|
||||
|
||||
# 伪目标
|
||||
.PHONY:clean
|
||||
|
||||
# 自动变量
|
||||
$@ 目标文件
|
||||
$< 第一个依赖文件
|
||||
$^ 全部的依赖文件
|
||||
|
||||
# 普通变量定义
|
||||
## 普通变量定义
|
||||
OPTION = -O3 -Wall
|
||||
|
||||
# 变量使用
|
||||
## 变量使用
|
||||
g++ $(OPTION) xxx
|
||||
|
||||
# 使用通配符
|
||||
%.o: %.c
|
||||
g++ $(OPTION) -c $< -o $@
|
||||
### 1. 变量和赋值
|
||||
Makefile 支持多种变量赋值方式:
|
||||
|
||||
- **`=`**:递归展开变量,变量值在使用时展开。
|
||||
- **`:=`**:简单展开变量,变量值在定义时展开。
|
||||
- **`?=`**:条件赋值,只有当变量未定义时才赋值。
|
||||
- **`+=`**:追加赋值,将值追加到变量末尾。
|
||||
|
||||
```makefile
|
||||
.PHONY:clean
|
||||
INCLUDE = -I/home/e0x2d/include
|
||||
main: file1.o file2.o
|
||||
g++ -o $@ file1.o file2.o
|
||||
|
||||
file1.o: file1.cpp
|
||||
g++ -c file1.o file1.cpp
|
||||
|
||||
file2.o: file2.cpp
|
||||
g++ -c file2.o file2.cpp ${INCLUDE}
|
||||
|
||||
clean:
|
||||
rm *.o demo
|
||||
CC = gcc
|
||||
CFLAGS := -Wall -O2
|
||||
CFLAGS += -g
|
||||
```
|
||||
|
||||
### 2. 自动变量
|
||||
Makefile 提供了一些自动变量,用于简化规则的编写:
|
||||
|
||||
- **`$@`**:目标文件名。
|
||||
- **`$<`**:第一个依赖文件名。
|
||||
- **`$^`**:所有依赖文件列表。
|
||||
- **`$?`**:所有比目标新的依赖文件列表。
|
||||
- **`$*`**:目标文件的主干名(不包含扩展名)。
|
||||
|
||||
```makefile
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
```
|
||||
|
||||
### 3. 模式规则
|
||||
模式规则允许你使用通配符来定义规则,适用于多个文件。
|
||||
|
||||
```makefile
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
```
|
||||
|
||||
### 4. 函数
|
||||
Makefile 提供了一些内置函数,用于处理字符串、文件名等。
|
||||
|
||||
- **`$(wildcard pattern)`**:匹配文件名模式。
|
||||
- **`$(patsubst pattern,replacement,text)`**:模式替换。
|
||||
- **`$(shell command)`**:执行 shell 命令并返回结果。
|
||||
- **`$(foreach var,list,text)`**:循环遍历列表。
|
||||
|
||||
```makefile
|
||||
SRCS = $(wildcard *.c)
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
```
|
||||
|
||||
### 5. 条件判断
|
||||
Makefile 支持条件判断,可以根据条件执行不同的操作。
|
||||
|
||||
```makefile
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -DDEBUG
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
endif
|
||||
```
|
||||
|
||||
### 6. 包含其他 Makefile
|
||||
你可以使用 `include` 指令将其他 Makefile 包含到当前 Makefile 中。
|
||||
|
||||
```makefile
|
||||
include config.mk
|
||||
```
|
||||
|
||||
### 7. 多目标规则
|
||||
你可以为一个规则定义多个目标,这样它们可以共享相同的命令。
|
||||
|
||||
```makefile
|
||||
all: target1 target2
|
||||
|
||||
target1 target2:
|
||||
@echo Building $@
|
||||
```
|
||||
|
||||
### 8. 伪目标
|
||||
伪目标是指那些不对应实际文件的目标,通常用于执行一些操作,如清理、安装等。
|
||||
|
||||
```makefile
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
```
|
||||
|
||||
### 9. 嵌套 Makefile
|
||||
你可以在 Makefile 中调用另一个 Makefile,通常用于构建子目录中的项目。
|
||||
|
||||
```makefile
|
||||
SUBDIRS = dir1 dir2
|
||||
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
|
||||
all: $(SUBDIRS)
|
||||
```
|
||||
|
||||
### 10. 自定义函数
|
||||
你可以通过 `define` 和 `endef` 定义自定义函数。
|
||||
|
||||
```makefile
|
||||
define greet
|
||||
@echo "Hello, $(1)!"
|
||||
endef
|
||||
|
||||
all:
|
||||
$(call greet,World)
|
||||
```
|
||||
|
||||
### 11. 错误处理
|
||||
你可以使用 `$(error text)` 和 `$(warning text)` 来生成错误或警告信息。
|
||||
|
||||
```makefile
|
||||
ifeq ($(CC),)
|
||||
$(error CC is not set)
|
||||
endif
|
||||
```
|
||||
|
||||
### 13. 隐式规则
|
||||
Makefile 有一些内置的隐式规则,可以自动推导如何从源文件生成目标文件。你可以通过定义自己的隐式规则来覆盖默认行为。
|
||||
|
||||
```makefile
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
```
|
||||
|
||||
### 14. 动态依赖
|
||||
你可以使用 `-include` 来包含动态生成的依赖文件,通常用于自动生成头文件依赖。
|
||||
|
||||
```makefile
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
%.d: %.c
|
||||
@$(CC) -MM $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$
|
||||
```
|
||||
|
||||
### 16. 环境变量
|
||||
Makefile 可以访问环境变量,并且可以通过 `export` 将变量传递给子 Makefile。
|
||||
|
||||
```makefile
|
||||
export PATH := $(PATH):/usr/local/bin
|
||||
```
|
||||
|
||||
### 17. 多行命令
|
||||
你可以使用反斜杠 `\` 将长命令分成多行。
|
||||
|
||||
```makefile
|
||||
all:
|
||||
@echo "This is a long command that spans \
|
||||
multiple lines."
|
||||
```
|
||||
|
||||
### 18. 命令前缀
|
||||
命令前缀可以控制命令的执行方式:
|
||||
|
||||
- **`@`**:不显示命令本身,只显示输出。
|
||||
- **`-`**:忽略命令的错误,继续执行。
|
||||
|
||||
```makefile
|
||||
all:
|
||||
@echo "This command will not be displayed"
|
||||
-rm -f non_existent_file
|
||||
```
|
||||
|
||||
### 19. 文件搜索路径
|
||||
你可以使用 `VPATH` 或 `vpath` 来指定源文件的搜索路径。
|
||||
|
||||
```makefile
|
||||
VPATH = src:include
|
||||
|
||||
vpath %.c src
|
||||
vpath %.h include
|
||||
```
|
||||
|
||||
### 20. 递归扩展变量
|
||||
递归扩展变量在使用时才会展开,可以用于动态生成内容。
|
||||
|
||||
```makefile
|
||||
FOO = $(BAR)
|
||||
BAR = $(BAZ)
|
||||
BAZ = Hello
|
||||
|
||||
all:
|
||||
@echo $(FOO) # 输出 Hello
|
||||
```
|
||||
|
||||
### 21. 静态模式规则
|
||||
静态模式规则允许你为特定目标定义规则。
|
||||
|
||||
```makefile
|
||||
objects = foo.o bar.o
|
||||
|
||||
$(objects): %.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
```
|
||||
|
||||
### 22. 多架构支持
|
||||
你可以通过条件判断来支持多架构编译。
|
||||
|
||||
```makefile
|
||||
ifeq ($(ARCH),x86)
|
||||
CFLAGS += -m32
|
||||
else ifeq ($(ARCH),x64)
|
||||
CFLAGS += -m64
|
||||
endif
|
||||
```
|
||||
|
||||
### 23. 自定义后缀规则
|
||||
你可以定义自定义的后缀规则来处理特定类型的文件。
|
||||
|
||||
```makefile
|
||||
.SUFFIXES: .cpp .o
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
```
|
||||
|
||||
### 24. 使用 `eval` 动态生成规则
|
||||
`eval` 函数可以动态生成 Makefile 规则。
|
||||
|
||||
```makefile
|
||||
define MAKE_RULE
|
||||
$(1): $(2)
|
||||
$(CC) $(CFLAGS) -c $$< -o $$@
|
||||
endef
|
||||
|
||||
$(eval $(call MAKE_RULE,foo.o,foo.c))
|
||||
```
|
||||
|
||||
### 25. 使用 `foreach` 循环
|
||||
`foreach` 函数可以用于循环处理列表中的每个元素。
|
||||
|
||||
```makefile
|
||||
DIRS = dir1 dir2 dir3
|
||||
|
||||
all:
|
||||
$(foreach dir,$(DIRS),$(MAKE) -C $(dir);)
|
||||
```
|
||||
|
||||
### 26. 使用 `call` 调用自定义函数
|
||||
`call` 函数可以调用自定义函数,并传递参数。
|
||||
|
||||
```makefile
|
||||
define greet
|
||||
@echo "Hello, $(1)!"
|
||||
endef
|
||||
|
||||
all:
|
||||
$(call greet,World)
|
||||
```
|
||||
|
||||
### 27. 使用 `shell` 函数执行外部命令
|
||||
`shell` 函数可以执行外部命令并返回结果。
|
||||
|
||||
```makefile
|
||||
DATE := $(shell date)
|
||||
```
|
||||
|
||||
### 28. 使用 `info` 和 `warning` 输出信息
|
||||
`info` 和 `warning` 函数可以用于输出信息。
|
||||
|
||||
```makefile
|
||||
$(info Building target $(TARGET))
|
||||
$(warning This is a warning message)
|
||||
```
|
||||
|
||||
### 29. 使用 `if` 条件判断
|
||||
`if` 函数可以用于条件判断。
|
||||
|
||||
```makefile
|
||||
DEBUG = 1
|
||||
|
||||
CFLAGS += $(if $(DEBUG),-g,-O2)
|
||||
```
|
||||
|
||||
### 30. 使用 `or` 和 `and` 逻辑操作
|
||||
`or` 和 `and` 函数可以用于逻辑操作。
|
||||
|
||||
```makefile
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -g
|
||||
else ifeq ($(OPTIMIZE),1)
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
```
|
||||
|
||||
### 31. 使用 `not` 取反
|
||||
`not` 函数可以用于取反操作。
|
||||
|
||||
```makefile
|
||||
ifneq ($(DEBUG),1)
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
```
|
||||
|
||||
### 32. 使用 `filter` 和 `filter-out` 过滤列表
|
||||
`filter` 和 `filter-out` 函数可以用于过滤列表。
|
||||
|
||||
```makefile
|
||||
SRCS = foo.c bar.c baz.c
|
||||
|
||||
C_SRCS = $(filter %.c,$(SRCS))
|
||||
NON_C_SRCS = $(filter-out %.c,$(SRCS))
|
||||
```
|
||||
|
||||
### 33. 使用 `sort` 排序列表
|
||||
`sort` 函数可以用于排序列表。
|
||||
|
||||
```makefile
|
||||
SRCS = foo.c bar.c baz.c
|
||||
|
||||
SORTED_SRCS = $(sort $(SRCS))
|
||||
```
|
||||
|
||||
### 34. 使用 `strip` 去除空格
|
||||
`strip` 函数可以用于去除字符串中的空格。
|
||||
|
||||
```makefile
|
||||
STR = foo bar
|
||||
|
||||
STRIPED_STR = $(strip $(STR))
|
||||
```
|
||||
|
||||
### 35. 使用 `findstring` 查找子字符串
|
||||
`findstring` 函数可以用于查找子字符串。
|
||||
|
||||
```makefile
|
||||
ifeq ($(findstring foo,$(STR)),foo)
|
||||
@echo "Found foo"
|
||||
endif
|
||||
```
|
||||
|
||||
### 36. 使用 `subst` 替换字符串
|
||||
`subst` 函数可以用于替换字符串。
|
||||
|
||||
```makefile
|
||||
STR = foo bar baz
|
||||
|
||||
NEW_STR = $(subst foo,FOO,$(STR))
|
||||
```
|
||||
|
||||
### 37. 使用 `patsubst` 模式替换
|
||||
`patsubst` 函数可以用于模式替换。
|
||||
|
||||
```makefile
|
||||
SRCS = foo.c bar.c baz.c
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
```
|
||||
|
||||
### 38. 使用 `wildcard` 匹配文件名
|
||||
`wildcard` 函数可以用于匹配文件名。
|
||||
|
||||
```makefile
|
||||
SRCS = $(wildcard *.c)
|
||||
```
|
||||
|
||||
### 39. 使用 `dir` 和 `notdir` 获取目录和文件名
|
||||
`dir` 和 `notdir` 函数可以用于获取目录和文件名。
|
||||
|
||||
```makefile
|
||||
FILE = /path/to/file.c
|
||||
|
||||
DIR = $(dir $(FILE))
|
||||
NAME = $(notdir $(FILE))
|
||||
```
|
||||
|
||||
### 40. 使用 `suffix` 和 `basename` 获取后缀和主干名
|
||||
`suffix` 和 `basename` 函数可以用于获取文件的后缀和主干名。
|
||||
|
||||
```makefile
|
||||
FILE = file.c
|
||||
|
||||
SUFFIX = $(suffix $(FILE))
|
||||
BASENAME = $(basename $(FILE))
|
||||
```
|
||||
|
||||
### 41. 使用 `addsuffix` 和 `addprefix` 添加后缀和前缀
|
||||
`addsuffix` 和 `addprefix` 函数可以用于添加后缀和前缀。
|
||||
|
||||
```makefile
|
||||
FILES = foo bar baz
|
||||
|
||||
FILES_WITH_SUFFIX = $(addsuffix .c,$(FILES))
|
||||
FILES_WITH_PREFIX = $(addprefix src/,$(FILES))
|
||||
```
|
||||
|
||||
### 42. 使用 `join` 连接列表
|
||||
`join` 函数可以用于连接两个列表。
|
||||
|
||||
```makefile
|
||||
LIST1 = foo bar
|
||||
LIST2 = baz qux
|
||||
|
||||
JOINED_LIST = $(join $(LIST1),$(LIST2))
|
||||
```
|
||||
|
||||
### 43. 使用 `word` 和 `wordlist` 获取列表中的元素
|
||||
`word` 和 `wordlist` 函数可以用于获取列表中的元素。
|
||||
|
||||
```makefile
|
||||
LIST = foo bar baz
|
||||
|
||||
FIRST = $(word 1,$(LIST))
|
||||
SUBLIST = $(wordlist 2,3,$(LIST))
|
||||
```
|
||||
|
||||
### 44. 使用 `words` 获取列表长度
|
||||
`words` 函数可以用于获取列表的长度。
|
||||
|
||||
```makefile
|
||||
LIST = foo bar baz
|
||||
|
||||
LENGTH = $(words $(LIST))
|
||||
```
|
||||
|
||||
### 45. 使用 `firstword` 获取列表的第一个元素
|
||||
`firstword` 函数可以用于获取列表的第一个元素。
|
||||
|
||||
```makefile
|
||||
LIST = foo bar baz
|
||||
|
||||
FIRST = $(firstword $(LIST))
|
||||
```
|
||||
|
||||
### 46. 使用 `lastword` 获取列表的最后一个元素
|
||||
`lastword` 函数可以用于获取列表的最后一个元素。
|
||||
|
||||
```makefile
|
||||
LIST = foo bar baz
|
||||
|
||||
LAST = $(lastword $(LIST))
|
||||
```
|
||||
|
||||
### 47. 使用 `abspath` 获取绝对路径
|
||||
`abspath` 函数可以用于获取绝对路径。
|
||||
|
||||
```makefile
|
||||
FILE = file.c
|
||||
|
||||
ABS_PATH = $(abspath $(FILE))
|
||||
```
|
||||
|
||||
### 48. 使用 `realpath` 获取规范化的绝对路径
|
||||
`realpath` 函数可以用于获取规范化的绝对路径。
|
||||
|
||||
```makefile
|
||||
FILE = ../file.c
|
||||
|
||||
REAL_PATH = $(realpath $(FILE))
|
||||
```
|
||||
|
37
radio/antenna.md
Normal file
37
radio/antenna.md
Normal file
@ -0,0 +1,37 @@
|
||||
# 天线相关
|
||||
|
||||
## index
|
||||
- [极化](# 极化)
|
||||
|
||||
## 极化
|
||||
在无线电通信中,垂直极化和水平极化是两种常见的天线极化方式,它们的区别主要体现在电磁波的振动方向、传播特性以及应用场景上。以下是具体对比:
|
||||
|
||||
### **1. 极化方向**
|
||||
- **垂直极化**:电磁波的电场分量(E-field)与地面垂直振动,天线通常垂直于地面放置(如直立杆状天线)。
|
||||
- **水平极化**:电磁波的电场分量与地面平行振动,天线通常水平架设(如水平拉长的偶极天线)。
|
||||
|
||||
### **2. 传播特性**
|
||||
- **地面反射影响**:
|
||||
- 垂直极化波在地面反射时相位变化较小,更适合地面波传播(如AM广播、车载通信)。
|
||||
- 水平极化波的地面反射可能导致信号抵消(尤其在仰角较低时),但对天波传播(如短波通信)更有利。
|
||||
- **抗干扰能力**:
|
||||
- 垂直极化更容易受到地面物体(如建筑物、树木)的反射干扰。
|
||||
- 水平极化受地面干扰较小,但在城市环境中可能受多径效应影响。
|
||||
|
||||
### **3. 应用场景**
|
||||
- **垂直极化**:
|
||||
- **移动通信**(如车载天线、对讲机):便于安装,适应移动设备姿态变化。
|
||||
- **低频段通信**(如30MHz以下):地波传播效率高。
|
||||
- **水平极化**:
|
||||
- **电视广播**(传统地面电视):减少地面反射干扰,覆盖更稳定。
|
||||
- **卫星通信**:减少电离层对极化旋转的影响(常与圆极化结合使用)。
|
||||
- **短波通信**:利用电离层反射时效率更高。
|
||||
|
||||
### **4. 天线安装与兼容性**
|
||||
- **极化匹配**:
|
||||
- 收发天线极化方式需一致,否则会导致严重信号衰减(如垂直天线无法有效接收水平极化波)。
|
||||
- 特殊场景(如卫星通信)可能采用圆极化以避免极化失配。
|
||||
|
||||
### **总结选择依据**
|
||||
- **优先垂直极化**:移动通信、地波传播、简化安装。
|
||||
- **优先水平极化**:固定点对点通信、减少地面干扰、高频段应用。
|
@ -1,15 +0,0 @@
|
||||
加速器
|
||||
https://cloud.tsinghua.edu.cn/d/df482a15afb64dfeaff8/
|
||||
推送到github
|
||||
git remote add origin https://
|
||||
git branch -M master
|
||||
git push -u origin master
|
||||
|
||||
github访问令牌
|
||||
创建:
|
||||
用户头像 -> setting -> 最后一项 -> 创建令牌
|
||||
tips:令牌要当场复制,离开页面就没有了
|
||||
|
||||
使用:
|
||||
git remote set-url origin https://<your_token>@github.com/<USERNAME>/<REPO>.git
|
||||
|
40
tool/git/github.md
Normal file
40
tool/git/github.md
Normal file
@ -0,0 +1,40 @@
|
||||
# github
|
||||
|
||||
## 目录
|
||||
- [search](#search)
|
||||
|
||||
## search
|
||||
|
||||
1. 限定搜索范围
|
||||
- `in:name`:搜索仓库名称。
|
||||
- `in:description`:搜索仓库描述。
|
||||
- 使用`is:issue`或`is:pr`搜索Issue或Pull Request。
|
||||
- **星标筛选**:使用`stars:>1000`筛选星标数超过1000的项目。
|
||||
- **fork数量筛选**:使用`forks:>100`筛选fork数量超过100的项目。
|
||||
- **语言筛选**:使用`language:java`筛选使用Java语言的项目。
|
||||
- **仓库大小筛选**:使用`size:>=1000`筛选仓库大小超过1000KB的项目。
|
||||
- **更新时间筛选**:使用`pushed:>2020-01-01`筛选自2020年1月1日之后有更新的项目。
|
||||
- **搜索特定用户或组织的仓库**:使用`user:username`或`org:organization`。
|
||||
- **搜索特定文件**:使用`filename:README.md`搜索包含特定文件名的项目。
|
||||
- **搜索代码**:必须登录GitHub账户,且仅对默认分支和小于384KB的文件进行索引。
|
||||
|
||||
2. 排序搜索结果
|
||||
- **按交互排序**:`sort:interactions`按反应和评论的最高组合数排序。
|
||||
- **按反应排序**:`sort:reactions`按最高反应数排序。
|
||||
- **按作者日期排序**:`sort:author-date`按作者日期降序排序。
|
||||
|
||||
加速器
|
||||
https://cloud.tsinghua.edu.cn/d/df482a15afb64dfeaff8/
|
||||
推送到github
|
||||
git remote add origin https://
|
||||
git branch -M master
|
||||
git push -u origin master
|
||||
|
||||
github访问令牌
|
||||
创建:
|
||||
用户头像 -> setting -> 最后一项 -> 创建令牌
|
||||
tips:令牌要当场复制,离开页面就没有了
|
||||
|
||||
使用:
|
||||
git remote set-url origin https://<your_token>@github.com/<USERNAME>/<REPO>.git
|
||||
|
31
tool/konsole.md
Normal file
31
tool/konsole.md
Normal file
@ -0,0 +1,31 @@
|
||||
# konsole-use
|
||||
|
||||
## 目录
|
||||
|
||||
- [strat](#start)
|
||||
- [标签页管理](#标签页管理)
|
||||
- [窗口分割](#窗口分割)
|
||||
- [shortkey](#shortkey)
|
||||
|
||||
## strat
|
||||
`Ctrl-Alt-t`
|
||||
|
||||
## 标签页管理
|
||||
`Ctrl-T` 打开新标签页
|
||||
`Ctrl-W` 关闭标签页
|
||||
`Ctrl-PgUp` and `Ctrl-PgDn` 切换标签页
|
||||
`Alt-[num]` 切换到指定标签页
|
||||
|
||||
## 窗口分割
|
||||
`Ctrl-(` 水平分割
|
||||
`Ctrl-)` 垂直分割
|
||||
`Ctrl-Shift-方向键` 聚焦指定方向的终端
|
||||
`Ctrl-Shift-H` 分离
|
||||
|
||||
## shortkey
|
||||
`Ctrl-F` 查找
|
||||
`Shift-F3` 查找上一个
|
||||
`F3` 查找下一个
|
||||
|
||||
`Shift-F10` 打开菜单
|
||||
|
@ -14,28 +14,73 @@ set cursorline "光标行高亮
|
||||
set hlsearch "高亮显示搜索结果
|
||||
set incsearch "搜索模式下,每输入一个字符,就跳到对应结果
|
||||
set ignorecase "忽略搜索大小写
|
||||
set tags=./tags;,tags "表示从当前文件所在的目录开始查找 tags 文件,如果没有,则向上递归查找
|
||||
|
||||
|
||||
"缓冲区操作
|
||||
nnoremap <space>b :buffers<cr>:b<space>
|
||||
nnoremap <space>e :b#<cr>
|
||||
nnoremap <space>n :bnext<cr>
|
||||
|
||||
"页面分割操作
|
||||
nnoremap <space>s :split<space>
|
||||
nnoremap <space>v :vsp<space>
|
||||
nnoremap <space>d <c-w>w
|
||||
|
||||
"保存
|
||||
nnoremap <space>w :w<cr>
|
||||
nnoremap <space>q :q<cr>
|
||||
nnoremap <space>fq :q!<cr>
|
||||
nnoremap <space>pq :%s/\t/ /g<cr>:wq<cr>
|
||||
|
||||
"多标签页
|
||||
nnoremap <space>tt :tabedit<space>
|
||||
nnoremap <space>tm :vert term<cr>
|
||||
|
||||
"操作优化
|
||||
nnoremap gm $
|
||||
nnoremap <space>r :reg<cr>
|
||||
inoremap jf <esc>
|
||||
inoremap jl <c-x><c-l>
|
||||
cnoremap jf <c-c>
|
||||
"inoremap jq <esc>:wq<cr>
|
||||
"inoremap jw <c-x><c-n>
|
||||
"nnoremap <space>to :tabonly<cr>
|
||||
vnoremap gm $
|
||||
inoremap ! !
|
||||
inoremap ( (
|
||||
inoremap ) )
|
||||
inoremap 【 [
|
||||
inoremap 】 ]
|
||||
inoremap ; ;
|
||||
inoremap : :
|
||||
inoremap ‘ '
|
||||
inoremap “ "
|
||||
inoremap , ,
|
||||
inoremap 。 .
|
||||
inoremap ? ?
|
||||
inoremap 《 <
|
||||
inoremap 》 >
|
||||
inoremap · `
|
||||
|
||||
"自动补全
|
||||
inoremap jl <c-x><c-l>
|
||||
inoremap jbf <c-x><c-f>
|
||||
inoremap jk <c-x><c-k>
|
||||
|
||||
" 启用字典补全(Ctrl-X Ctrl-K)
|
||||
set complete+=k
|
||||
|
||||
" 加载字典补全功能
|
||||
|
||||
" 根据文件类型设置不同的字典文件
|
||||
autocmd FileType c setlocal dictionary+=~/.vim/dict/cpp.dict
|
||||
autocmd FileType cpp setlocal dictionary+=~/.vim/dict/cpp.dict
|
||||
"autocmd FileType python setlocal dictionary+=~/.vim/dict/python.dict
|
||||
"autocmd FileType javascript setlocal dictionary+=~/.vim/dict/javascript.dict
|
||||
"autocmd FileType html setlocal dictionary+=~/.vim/dict/html.dict
|
||||
"autocmd FileType css setlocal dictionary+=~/.vim/dict/css.dict
|
||||
|
||||
|
||||
augroup numbertoggle "智能切换绝对行号和相对行号
|
||||
autocmd!
|
||||
autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu && mode() != "i" | set rnu | endif
|
||||
autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif
|
||||
augroup END
|
||||
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
# 小技巧
|
||||
使用 q[Key] 开始录制宏,再次点击q结束录制
|
||||
@[Key] 调用宏
|
||||
@@ 重复调用
|
||||
|
||||
# vim中打开终端
|
||||
`:term`或`:vert term`
|
||||
从终端转到普通模式:`<c-\>+<c-n>`
|
||||
|
||||
# 快捷键
|
||||
|
||||
> 移动
|
||||
## 0 gm
|
||||
行首行尾移动
|
||||
## ngg
|
||||
移动到第n行
|
||||
## fc tc
|
||||
搜索字符 ; , 可重复
|
||||
|
||||
> 插入
|
||||
## r R
|
||||
替换光标下的字符
|
||||
## n<< n>>
|
||||
多行左右移动
|
||||
|
||||
|
||||
> 删除
|
||||
## x
|
||||
删除光标下字符
|
||||
## J
|
||||
与下一行合并
|
||||
|
||||
> 复制
|
||||
## "x
|
||||
使用寄存器x进行下一次复制 粘贴 删除
|
||||
:reg 显示所有寄存器
|
||||
|
||||
|
||||
> 可视模式
|
||||
## o
|
||||
交换选择区域另一端和光标的位置
|
||||
## aw as ap ab aB
|
||||
选择一个单词 句子 段落 () {}
|
||||
## vi{
|
||||
选中一整个大括号内
|
||||
## va{
|
||||
选中一整个大括号全部
|
||||
|
||||
|
||||
## ]f
|
||||
在文件中若出现文件名,指针放在上面使用这个快捷键可直接打开
|
||||
|
157
tool/vim/cpp.dict
Normal file
157
tool/vim/cpp.dict
Normal file
@ -0,0 +1,157 @@
|
||||
include
|
||||
auto
|
||||
break
|
||||
case
|
||||
char
|
||||
const
|
||||
continue
|
||||
default
|
||||
do
|
||||
double
|
||||
else
|
||||
enum
|
||||
extern
|
||||
float
|
||||
for
|
||||
goto
|
||||
if
|
||||
int
|
||||
long
|
||||
register
|
||||
return
|
||||
short
|
||||
signed
|
||||
sizeof
|
||||
static
|
||||
struct
|
||||
switch
|
||||
typedef
|
||||
union
|
||||
unsigned
|
||||
void
|
||||
volatile
|
||||
while
|
||||
|
||||
class
|
||||
delete
|
||||
explicit
|
||||
friend
|
||||
inline
|
||||
namespace
|
||||
new
|
||||
operator
|
||||
private
|
||||
protected
|
||||
public
|
||||
template
|
||||
this
|
||||
throw
|
||||
try
|
||||
catch
|
||||
virtual
|
||||
using
|
||||
typename
|
||||
mutable
|
||||
const_cast
|
||||
dynamic_cast
|
||||
reinterpret_cast
|
||||
static_cast
|
||||
typeid
|
||||
endl
|
||||
|
||||
printf
|
||||
scanf
|
||||
fopen
|
||||
fclose
|
||||
fgets
|
||||
fputs
|
||||
fread
|
||||
fwrite
|
||||
sprintf
|
||||
sscanf
|
||||
|
||||
malloc
|
||||
free
|
||||
calloc
|
||||
realloc
|
||||
exit
|
||||
atoi
|
||||
atof
|
||||
rand
|
||||
srand
|
||||
|
||||
strcpy
|
||||
strncpy
|
||||
strcat
|
||||
strncat
|
||||
strcmp
|
||||
strncmp
|
||||
strlen
|
||||
strstr
|
||||
strtok
|
||||
memset
|
||||
memcpy
|
||||
memmove
|
||||
|
||||
sin
|
||||
cos
|
||||
tan
|
||||
sqrt
|
||||
pow
|
||||
log
|
||||
exp
|
||||
ceil
|
||||
floor
|
||||
fabs
|
||||
|
||||
time
|
||||
clock
|
||||
difftime
|
||||
gmtime
|
||||
localtime
|
||||
strftime
|
||||
|
||||
vector
|
||||
list
|
||||
map
|
||||
unordered_map
|
||||
set
|
||||
unordered_set
|
||||
queue
|
||||
stack
|
||||
deque
|
||||
pair
|
||||
tuple
|
||||
|
||||
sort
|
||||
find
|
||||
copy
|
||||
transform
|
||||
accumulate
|
||||
for_each
|
||||
count
|
||||
reverse
|
||||
max_element
|
||||
min_element
|
||||
|
||||
define
|
||||
NULL
|
||||
EOF
|
||||
true
|
||||
false
|
||||
stdin
|
||||
stdout
|
||||
stderr
|
||||
EXIT_SUCCESS
|
||||
EXIT_FAILURE
|
||||
|
||||
open
|
||||
close
|
||||
read
|
||||
write
|
||||
fork
|
||||
exec
|
||||
pipe
|
||||
dup2
|
||||
select
|
||||
poll
|
89
tool/vim/shortcutKeys.md
Normal file
89
tool/vim/shortcutKeys.md
Normal file
@ -0,0 +1,89 @@
|
||||
# vim小技巧
|
||||
`.` 重复上一个操作
|
||||
|
||||
## 目录
|
||||
- [录制宏](# 录制宏)
|
||||
- [打开终端](# 打开终端)
|
||||
- [快捷键](# 快捷键)
|
||||
- [移动](# 移动)
|
||||
- [插入](# 插入)
|
||||
- [修改](# 修改)
|
||||
- [删除](# 删除)
|
||||
- [复制](# 复制)
|
||||
- [基本补全](# 基本补全)
|
||||
- [补全菜单](# 补全菜单)
|
||||
- [vimrc](# ./.vimrc)
|
||||
|
||||
## 录制宏
|
||||
使用 q[Key] 开始录制宏,再次点击q结束录制
|
||||
@[Key] 调用宏
|
||||
@@ 重复调用
|
||||
|
||||
## 打开终端
|
||||
`:term`或`:vert term`
|
||||
从终端转到普通模式:`<c-\>+<c-n>`
|
||||
|
||||
## 快捷键
|
||||
### 移动
|
||||
+ 0 gm 行首行尾
|
||||
+ ngg 移动到第n行
|
||||
+ fc tc 搜索字符 ; , 可重复
|
||||
+ c-u 上半屏
|
||||
+ c-d 下半屏
|
||||
+ Shift-[ 跳转到上一个空行
|
||||
+ * 移动到下一个与当前指针下相同单词的位置
|
||||
+ # 移动到上一个与当前指针下相同单词的位置
|
||||
+ Ctrl + ] 跳转到标签,依赖于tags文件
|
||||
+ `ctags -R .` 创建目录下的跳转文件
|
||||
+ Vim 会记录跳转历史,使用 Ctrl + T 或 Ctrl + O 返回到上一个位置
|
||||
+ gf 跳转到文件路径
|
||||
+ `c-o` 后退一步
|
||||
+ `c-i` 前进一步
|
||||
+ `[a-z] / `[A-Z] 跳转到标记位置 大写全局,小写本文件,用m[a-z]设置标记
|
||||
+ ` 上次跳转的位置
|
||||
+ . 最后一次修改的位置
|
||||
|
||||
### 插入
|
||||
+ I A 行首 行末 插入
|
||||
+ n<< n>> 多行左右移动
|
||||
|
||||
## 修改
|
||||
+ r R 替换光标下的字符
|
||||
+ c-i-( 替换括号内的内容可以使用任何括号匹配
|
||||
|
||||
### 删除
|
||||
+ x 删除光标下字符
|
||||
+ J 与下一行合并
|
||||
+ Shift-d 从当前字符删除到行末
|
||||
|
||||
### 复制
|
||||
+ "x 使用寄存器x进行下一次复制 粘贴 删除
|
||||
:reg 显示所有寄存器
|
||||
|
||||
### 可视模式
|
||||
+ o
|
||||
交换选择区域另一端和光标的位置
|
||||
+ aw as ap ab aB
|
||||
选择一个单词 句子 段落 () {}
|
||||
+ vi{
|
||||
选中一整个大括号内
|
||||
+ va{
|
||||
选中一整个大括号全部
|
||||
+ ]f
|
||||
在文件中若出现文件名,指针放在上面使用这个快捷键可直接打开
|
||||
|
||||
## 基本补全
|
||||
1. Ctrl+n - 普通关键字补全(向下浏览)
|
||||
- 在当前文件和包含文件中查找匹配项
|
||||
- 适用于变量名、函数名等
|
||||
2. Ctrl+p - 普通关键字补全(向上浏览)
|
||||
- 与 Ctrl+n 相同,只是方向相反
|
||||
3. Ctrl+x Ctrl+f - 文件名补全
|
||||
- 在输入路径时自动补全文件名
|
||||
4. Ctrl+x Ctrl+l - 整行补全
|
||||
- 补全整行代码(从当前文件中查找相似行)
|
||||
|
||||
### 补全菜单
|
||||
1. `c-n``c-p` 上下移动
|
||||
2. `c-y` 确认
|
||||
3. `c-e` 退出
|
Loading…
x
Reference in New Issue
Block a user