跳转至

2023

Colorful Commands

导言

电脑玩家经常说RGB是最重要的,对于程序员来说,彩色的terminal有助于快速的分辨输出的有效信息。为此有一些有意思的彩色输出命令。

Cheat sheet (命令行小抄/备忘录)

最经典 tdlr

使用时需要网络

npm install -g tldr     
pip3 install tldr     
tealdeer - simplest example

a RUST fast version oftdlr

Tips: OpenSSL development headers get a "failed to run custom build command for openssl-sys" error message. The package is calledlibssl-dev on Ubuntu.

# install
cargo install tealdeer

# 使用
tdlr <>

部分支持中文,支持多平台

自定义
  1. cheat + 编写的cheatsheets
    1. 支持fzf和自动补全
  2. kb. A minimalist knowledge base manager
  3. eg provides examples of common uses of command line tools.
支持在线网页版
  1. Linux Command Line Cheat Sheet
  2. devhints.io
  3. 各种的选项,不止命令,包括bash, vim, mysql, git
  4. 语言 go, python, java, JS, NodeJS, Ruby 3.
  5. navi
  6. 支持语意转换的补全 🔥
  7. cheat.sh 🔥
  8. 支持 curl命令直接访问或者交互式
  9. 支持补全
  10. 返回内容集成cheat cheat.sheets tdlr
  11. bropages.org
  12. 用户自发投票排序的命令用例
navi installation & usage
# install
cargo install --locked navi

# download default cheatsheet
navi repo add denisidoro/cheats 

# 使用
navi
# 基于fzf寻找需要指令

SHELL

oh my zsh

虽然这个ohmyzsh好用,但是我用惯了hyq的模板, 从github上下载后解压就安装了zsh模板。(之后可以考虑传到云盘或者cloudflare)

HOME=/home/xxx
export SHELL=zsh
export PATH=$HOME/.local/bin:$PATH
export HISTFILE=$HOME/.zsh_history
zsh
git clone https://github.com/Kirrito-k423/QuickStartLinux.git
cd QuickStartLinux/resources
tar xvf zsh.tar -C $HOME

zsh_history 支持多端口同步,实时保存

~/.zshrc
HISTFILE=~/.zsh_history
SAVEHIST=10000 # 最多 10000 条命令的历史记录
setopt APPEND_HISTORY #  退出 zsh 会话时,命令不会被覆盖式地写入到历史文件,而是追加到该文件的末尾
setopt INC_APPEND_HISTORY # 会话进行中也会将命令追加到历史文件中
setopt SHARE_HISTORY # 所有会话中输入的命令保存到一个共享的历史列表中
export HIST_SAVE_FREQ=10  # 每10次命令保存一次
cd ~

窗口管理器 tmux-like

oh my tmux 🔥
## Install
cd
git clone https://github.com/gpakosz/.tmux.git
ln -s -f .tmux/.tmux.conf
cp .tmux/.tmux.conf.local .

# or
cd ~/resources
# wget https://gitee.com/shaojiemike/oh-my-tmux/repository/blazearchive/master.zip?Expires=1629202041&Signature=Iiolnv2jN6GZM0hBWY09QZAYYPizWCutAMAkhd%2Bwp%2Fo%3D
unzip  oh-my-tmux-master.zip -d ~/
ln -s -f ~/oh-my-tmux-master/.tmux.conf ~/.tmux.conf
cp ~/oh-my-tmux-master/.tmux.conf.local ~/.tmux.conf.local
基于Rust的zellij

开发编辑器 vim-like

vimrc 🔥
git clone --depth=1 https://github.com/amix/vimrc.git ~/.vim_runtime
sh ~/.vim_runtime/install_awesome_vimrc.sh
emacs

针对不同语言有许多可选插件

### Ubuntu install emacs27

add-apt-repository ppa:kelleyk/emacs
apt-get update
apt-get install emacs27

#### 问题:

dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Errors were encountered while processing:
/var/cache/apt/archives/emacs27-common_27.1~1.git86d8d76aa3-kk2+20.04_all.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

版本解决,强制安装 sudo apt-get -o Dpkg::Options::="--force-overwrite" install emacs27-common

sudo apt --purge remove emacs27
sudo apt --purge remove emacs
sudo apt --purge remove emacs-common
sudo apt --fix-broken install
sudo apt autoremove
sudo apt install emacs27
emacs --version
doom

### install doom

git clone --depth 1 https://github.com/doomemacs/doomemacs ~/.emacs.d
~/.emacs.d/bin/doom install

中文教程 https://www.bilibili.com/read/cv11371146

常用命令的"Colorful"版本

cd

z.lua - learning cd 🔥

Install LUA

```sh curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz tar zxf lua-5.4.4.tar.gz cd lua-5.4.4 make all test sudo make install # usr/bin

Install

  ```sh
  cd ~/github
  git clone https://github.com/skywind3000/z.lua.git

  # vim ~/.zshrc
  alias zz='z -c' # 严格匹配当前路径的子路径
  alias zi='z -i' # 使用交互式选择模式
  alias zf='z -I' # 使用 fzf 对多个结果进行选择
  alias zb='z -b' # 快速回到父目录
  #eval "$(lua /path/to/z.lua  --init zsh)"    # ZSH 初始化
  eval "$(lua ~/github/z.lua/z.lua  --init zsh)"
  ```

常用命令

  ```sh
  # 弹出栈顶 (cd 到上一次的老路径),和 "z -0" 相同
  $ z -

  # 显示当前的 dir stack
  $ z --

  # 交互式
  z -i foo    # 进入交互式选择模式,让你自己挑选去哪里(多个结果的话)
  z -I foo    # 进入交互式选择模式,但是使用 fzf 来选择

  # 匹配
  z foo$
  ```

```sh       
z foo       # 跳转到包含 foo 并且权重(Frecent)最高的路径       
z foo bar   # 跳转到同时包含 foo 和 bar 并且权重最高的路径       
z -r foo    # 跳转到包含 foo 并且访问次数最高的路径       
z -t foo    # 跳转到包含 foo 并且最近访问过的路径       
z -l foo    # 不跳转,只是列出所有匹配 foo 的路径       
z -c foo    # 跳转到包含 foo 并且是当前路径的子路径的权重最高的路径       
z -e foo    # 不跳转,只是打印出匹配 foo 并且权重最高的路径       
z -i foo    # 进入交互式选择模式,让你自己挑选去哪里(多个结果的话)       
z -I foo    # 进入交互式选择模式,但是使用 fzf 来选择       
z -b foo    # 跳转到父目录中名称以 foo 开头的那一级       

缺点:

  • 没去过的路径,每级文件夹的补全没有了
  • 可以和cd结合使用

ls

exa 🔥 - better ls
# Manual installation from GitHub. Ubuntu 20.10才支持
wget https://github.com/ogham/exa/releases/download/v0.10.1/exa-linux-x86_64-musl-v0.10.1.zip
unzip exa-linux-x86_64-musl-v0.10.1.zip
mv bin/exa ~/.local/bin

# 使用
exa -l
# 文件夹大小
du -d 1 -h .

grep

rg (Fast & Good multi-platform compatibility) > ag > ack(ack-grep) 🔥

repgrep(rg) Rust编写
# ripgrep(rg) 但是readme说这样有bugs       
sudo apt-get install ripgrep       
# 可执行文件 (推荐)    
wget https://github.com/BurntSushi/ripgrep/releases/download/13.0.0/ripgrep-13.0.0-x86_64-unknown-linux-musl.tar.gz      
tar -zxvf ripgrep-13.0.0-x86_64-unknown-linux-musl.tar.gz       
mv ./ripgrep-13.0.0-x86_64-unknown-linux-musl/rg ~/.local/bin       

repgrep(rg) 常用选项

  • --no-ignore 忽略.gitignore之类的文件,也搜索忽略的文件。(默认是不搜索的)
  • -t txt 指定搜索类型
  • rg 'content' ABC/*.cpp搜索和正则ABC/*.cpp匹配的文件
ag
# ag 2020年就不维护了       
apt-get install silversearcher-ag       
# It ignores file patterns from your .gitignore and .hgignore.       
# use -u or -U option to reinclude these files to search scoop       

find

fzf 🔥带预览的find
# ubuntu
sudo apt install fzf

# GIT install
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
source ~/.zshrc
# Vim-plugin
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }

# 使用
fzf --preview 'less {}'

# 安装了bat
fzf --preview "batcat --style=numbers --color=always --line-range :500 {}"
telescope.nvim 也带预览的find

官网

# 先安装vim-plug
curl -fLo~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
# 修改~/.vimrc
call plug#begin()
Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-telescope/telescope.nvim'
call plug#end()

# 还需要 Neovim
to do
fdfind(fd)

A simple, fast and user-friendly alternative to 'find'

cat

bat 🔥 - colorful cat
# Install
sudo apt install bat

# 使用
batcat filename
# 指定行号
alias cat="batcat"
cat -r 35:42 /etc/hosts

git

gitui 🔥 - fast Rust lazygit

https://github.com/extrawurst/gitui/releases

# 建议Rust,三句命令,安装Rust,source,gitui
curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env
cargo install gitui

# 安装(由于还在开发中建议去官网 , 现在不支持armV7
wget https://github.com/extrawurst/gitui/releases/download/v0.20.1/gitui-linux-musl.tar.gz
tar -zxvf gitui-linux-musl.tar.gz
mv gitui ~/.local/bin
lazygit
# install go
wget https://go.dev/dl/go1.18.1.linux-amd64.tar.gz

git clone https://github.com/jesseduffield/lazygit.git
cd lazygit
go install

高亮终端输出/log文件

bash脚本输出颜色文本示例

RED='\033[0;31m'       
NC='\033[0m' 
# No Color       
printf "I ${RED}love${NC} Stack Overflow\n"       
echo -e "\033[5;36m Orz 旧容器(镜像)已清理\033[0m"       

颜色编号如下

颜色 编号
Black 0;30
Dark Gray 1;30
Red 0;31
Light Red 1;31
Green 0;32
Light Green 1;32
Brown/Orange 0;33
Yellow 1;33
Blue 0;34
Light Blue 1;34
Purple 0;35
Light Purple 1;35
Cyan 0;36
Blue 0;37
Light Cyan 1;36
Light Gray 0;37
White 1;37
hl 🔥自定义高亮各种log文件

通过regular expressions自定义高亮各种log文件

install需要 lex

git clone https://github.com/mbornet-hl/hl       
make clean; 
make      
cp hl /usr/local/bin 
# move       

颜色支持(3浅中深 * 6颜色 * 背景色反转)

# 前面 123 是深浅 , 4是下划线       
# 字母大写是背景色反转       
-r : red        -g : green        -y : yellow        -b : blue        -m : magenta        -c : cyan        -w : white        

正则标记log关键词

绿色和红色

cat exemple.log | hl -g start -r stop       

正则表示

-e : extended regular expressions
-i : ignore case

hl -ei -g '(start(|ing|ed))' -r '(stop(|ping|ped))'

## ip 匹配
curl --trace-ascii - www.baidu.com|hl -ei -1R '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'

命令配置文件 hl_ha.cfg

默认设置

export HL_CONF=/staff/shaojiemike/github/hl/config_files       
echo $HL_CONF       │/staff/shaojiemike/github/hl/config_files       
-%c : specifies the beginning of a range colorized in color 'c'       
-.  : specifies the end of the previous range       

Colorize hl configurations :

hl -vop '*' | hl --hl_conf       

example Commands

lD # ls by date       
lW # ls by week       
ifconfig -a | hl --ifconfig       
# ping tcpdump fdisk apt-get diff       
# ip ibstat iptables passwd       

errors

常用方式

~/.zshrc 里如下配置:

export HL_CONF=/home/shaojiemike/github/hl/config_files       
function my_hl(){          hl -eg '\$\{?[A-Z_]+\}?' -ec ' ([A-Z_-]+) ' -eic '(nothing|note)' -eiy ' (-([a-z_-]+))' -eiy '0x[0-9a-z]+' --errors -eig '(yes)' -eir '((^| )no($| ))|(none)|(not)|(null)|(please)|( id )' -ir error -ir wrong -ib '(line)|(file)' -eiy '(warn(|ing))|(wait)|(idle)|(skip)' -im return -ic '(checking)' -eiy ' (__(.*)__) ' -ei1W '((\w*/[.A-Za-z0-9_/-]*[A-Za-z0-9_/-]*)("|$)?)|((\w*/[.A-Za-z0-9_/-]*[A-Za-z0-9_/-]*)(")? ) ' -3B '[0-9][0-9.]+' -3B ' ([0-9])|(#[0-9]+)' -eig '(start(|ing))' -eir '(end(|ing))'       }       
alias ifconfig='ifconfig | hl --ifconfig'       
alias ip='ip a|hl --ip '       
alias df='df -h |hl --df'       
alias ibstat='ibstat |hl --ibstat'       

编译时如此使用make 2>&1|my_hl

系统信息

dua-cli - best disk space viewer 🔥

more

资源监控

资源监控软件netdata
  • netdata 默认挂载在http://127.0.0.1:19999/。想要WebUI运行 sudo netdata -i node5.acsalab.com
  • cpu, disk, memory, network,温度都有记录
  • arm下有问题,需要自己编译

资源监控命令bottom(htop like)
# install
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.6.8/bottom_0.6.8_amd64.deb
sudo dpkg -i bottom_0.6.8_amd64.deb

# 使用
btm

类似s-tui可以观察CPU 温度,频率

网络监控 bmon

bmon是类 Unix 系统中一个基于文本,简单但非常强大的网络监视和调试工具

Compile yourself

Install libconfuse

sh wget https://github.com/martinh/libconfuse/releases/download/v2.8/confuse-2.8.zip unzip confuse-2.8.zip && cd confuse-2.8 PATH=/usr/local/opt/gettext/bin:$PATH ./configure make make install Install bmon

sh git clone https://github.com/tgraf/bmon.git cd bmon ./autogen.sh ./configure make make install bmon

文件管理器

nnn 多平台

https://github.com/jarun/nnn#quickstart

很复杂,插件和快捷键超级多

sh # 版本很低 3.0 sudo apt-get install nnn # Q 退出

ranger 基于vi的支持预览的横向多级显示 🔥

https://github.com/ranger/ranger

pip install ranger-fm

# renger直接使用,方向键或者hjkl,可以直接跳转到vim修改
xplr - 筛选排序tips板 - 支持多选,正则查找, mov改名delete 🔥

https://github.com/sayanarijit/xplr

sh cargo install --locked --force xplr

参考文献

[C++ Basic] Grammar

概要

C++ 基础知识和语法,包括C++11,C++17,C++23的各种语言支持。

C++编程语言历史 和 设计思路

在纷繁多变的世界里茁壮成长:C++ 2006–2020

C 与 C++、java 的 区别

支持范式模板编程 (generic programming)

  1. 模板代码(增加泛型编程能力,类似python),
  2. 泛型编程是一种以通用性为中心的编程范式。在泛型编程中,程序通过使用参数化类型(或称为模板)来实现数据类型无关的算法和数据结构
  3. 强⼤的 Standard Template Library (STL) 标准库, 也是基于泛型编程的产物。
  4. 包括:容器、迭代器、算法和函数对象 四类
  5. 元编程(e.g., constexpr )编译时推导出变量是否为固定常数。
  6. 一些语法和关键字,增加了 new 和 delete,auto

支持面向对象编程 (object-oriented programming) 的拓展

  • 类和对象:C++允许定义类和创建对象。类是一种用户自定义的数据类型,可以包含成员变量和成员函数。对象是类的一个实例,可以通过类来创建多个对象。C语言中没有类和对象的概念,只能使用结构体和函数来组织数据和行为。
  • 封装:C++支持封装,可以将数据和相关的操作封装在一个类中,并使用访问修饰符来控制对类成员的访问权限。C语言没有封装的概念,所有的数据和函数都是公开的。
  • 继承:C++支持继承,允许创建派生类从基类继承属性和行为。继承可以实现代码重用和类的层次化。C语言没有继承的概念。
  • 多态:C++支持多态,允许通过基类指针或引用来调用派生类的虚函数,实现动态绑定和运行时多态性。C语言没有多态的概念。
  • 异常处理:C++提供异常处理机制,可以通过抛出和捕获异常来处理程序中的错误和异常情况。C语言没有内置的异常处理机制。
C++ 与 java 的区别
  1. 内存管理:C++中的内存管理是手动的,程序员需要显式地分配和释放内存。C++提供了new和delete关键字来进行动态内存分配和释放。Java中的内存管理是自动的,使用垃圾回收机制来自动管理内存,程序员不需要手动释放内存。
  2. 指针:C++支持指针操作,允许直接访问和修改内存地址。Java中没有指针的概念,所有的数据访问都是通过引用进行的。
  3. 运行环境:C++是一种编译型语言,源代码在编译后被转换为机器码,并直接在操作系统上运行。Java是一种解释型语言,源代码在编译后生成字节码,然后由Java虚拟机(JVM)解释执行。
  4. 平台依赖性:C++代码在不同的平台上需要重新编译,因为它直接与底层系统交互。Java代码是平台无关的,一次编译的字节码可以在任何支持Java虚拟机的平台上运行。

  5. C++更适合系统级编程、游戏开发等需要更高的性能和底层控制的场景。

  6. Java更适合企业级应用开发、网络编程等需要跨平台和可移植性的场景。

基础知识与坑

程序执行入口

The default program entry function is main, but can be changed in two situations:

  1. use stupid #define xxx main in header file to replace the name which maybe ignored by silly search bar in VSCODE.
  2. use -exxx compile flag

语句末尾的分号

  • 在 C++ 中,是否需要在语句的末尾使用分号(;)取决于上下文。
  • C++ 语法的基本规则是:分号用来标识一条语句的结束,而有些结构并不是严格的语句,因此不需要分号。

  • 声明(变量、类、结构体、枚举、函数原型、类型别名):都需要分号作为结束。

  • 函数定义控制语句(如 if, while, for)、复合语句{}) 不需要分号。
  • 预处理指令(如 #define, #include):不需要分号,因为它们不是 C++ 语法层面的内容。
  • 作用域结束的 } 不需要分号,但声明类或结构体时 } 后要加分号。

为什么类/结构体需要分号

C++ 中的类和结构体定义实际上是一种声明,它们的定义是一种复杂的声明语句,因此必须用分号来结束它们。

总结来说,分号用来结束语句,包括声明、表达式和执行体等,但当你定义一个复合结构(如函数定义、控制语句)时,不需要分号来结束复合结构的定义。

逗号运算符(Comma)

重名变量的优先级

int getKthAncestor(int node, int k) {
    int node= getKthAncestor(saved[node],--k);  
    return node;
}
 //为什么第二行的node会提前被修改为0,导致传入函数getKthAncestor的saved[node]的node值为0
 //如下去掉int,也不会错。因为int node 会初始化node为0
 int getKthAncestor(int node, int k) {
    node= getKthAncestor(saved[node],--k);  
    return node;
}

根据C++的作用域规则,内层的局部变量会覆盖外层的同名变量。因此,在第二行的语句中,node引用的是函数参数中的node,而不是你想要的之前定义的node。

为了避免这个问题,你可以修改代码,避免重复定义变量名。例如,可以将第二行的变量名改为newNode或其他不同的名称,以避免与函数参数名冲突。

运算符优先级

运算符性质:

  • 接受的操作数,
  • 优先级,
    • 特殊:逻辑和(&&)先于逻辑或(||)、四则运算先于位运算
    • 位运算优先级低于判断符号,记得写括号。
    • 赋值(=)优先级最低
  • 结合性,
    • 左结合性: 大部分运算(加减乘除)
    • 右结合性:赋值运算符。程序会先计算它右边的表达式的值,然后再计算它左边的表达式的值
  • 返回值
    • 赋值运算符的返回值是赋值后左操作数的引用

变量类型以及Macro constants

https://en.cppreference.com/w/cpp/language/types

https://en.cppreference.com/w/cpp/types/integer

//返回与平台相关的数值类型的极值
std::numeric_limits<double>::max()
std::numeric_limits<int>::min()

#include<limits.h>
INT_MAX
FLT_MAX (or DBL_MAX ) 
-FLT_MAX (or -DBL_MAX ) 

关键词

extern 
const
constexpr //C++11引入的关键字,用于编译时的常量与常量函数。
volatile    //是指每次需要引用某个变量的数据时,都必须从内存原地址读取,而不是编译器优化后寄存器间接读取.(必须写回内存,为了多进程并发而设计的。)
inline 

static 关键字

static 作⽤:控制变量的存储⽅式和作用范围(可⻅性)。

  1. 修饰局部变量
    • 存放位置:栈区 -> 静态数据区(data段或者bss段)
    • 生命周期:程序结束才会释放
    • 作用域:还是局部代码块
  2. 修饰函数与全局变量
    • 使其作用范围由全工程文件可见变成了本文件可见
  3. 修饰类内函数
    • 静态成员函数:使用"static"修饰的成员函数称为静态成员函数。静态成员函数与类的对象无关,可以在没有创建对象的情况下直接通过类名调用。这意味着它们不需要通过类的对象来访问,而是属于整个类的。举例
    • 静态成员函数没有隐式的this指针,因此不能直接访问非静态成员变量和非静态成员函数。静态成员函数可以访问类的静态成员变量和其他静态成员函数。
    • static 成员函数不能被 virtual 修饰, static 成员不属于任何对象或实例,所以加上 virtual没有任何实际意义;
      • 静态成员函数没有 this 指针,虚函数的实现是为每⼀个对象分配⼀个vptr 指针,⽽ vptr 是通过 this 指针调⽤的,所以不能为 virtual;虚函数的调⽤关系,this->vptr->ctable->virtual function。
  4. 修饰类内的变量
    • 存放位置:栈区 -> 静态数据区(data段或者bss段)
    • 生命周期:程序结束才会释放
    • 意味着下一次调用函数时,静态局部变量将保持上一次调用时的值。
    • 由于不再属于某个类对象,可以直接通过类名初始化 int MyClass::staticVariable = 10;
静态成员函数
#include <iostream>

class MyClass {
public:
    static void staticFunction() {
        std::cout << "This is a static member function." << std::endl;
    }
};

int main() {
    MyClass::staticFunction(); // 直接通过类名调用静态成员函数
    return 0;
}

const 关键字

当const修饰基本数据类型时,可以将其放置在类型说明符的前面或后面,效果是一样的。const关键字用于声明一个常量,即其值在声明后不可修改。

const int constantValue1 = 10; // const在类型说明符前
int const constantValue2 = 20; // const在类型说明符后

当const关键字位于指针变量或引用变量的左侧时,它用于修饰指针所指向的变量,即指针指向的内容为常量。当const关键字位于指针变量或引用变量的右侧时,它用于修饰指针或引用本身,即指针或引用本身是常量。

  1. 修饰指针指向的变量, 它指向的值不能修改:

    int x = 5;
    const int* ptr = &x;  // 指向常量整数的指针
    // *ptr = 10;        // 错误:不能通过const指针修改值
    x = 10;               // 合法:可以修改变量本身的值
    
  2. 修饰指针本身 ,它不能再指向别的变量,但指向(变量)的值可以修改。:

    const int y = 10;
    int* const ptr = &y;  // 常量指针指向整数
    // ptr = &x;         // 错误:不能修改指针本身
    // *ptr = 5;         // 合法:可以修改常量变量的值
    
  3. const int *const p3; //指向整形常量 的 常量指针 。它既不能再指向别的常量,指向的值也不能修改。

explicit

在C++, explicit 是一个关键字,用于修饰单参数构造函数,用于禁止隐式类型转换。

当一个构造函数被声明为 explicit 时,它指示编译器在使用该构造函数进行类型转换时只能使用显式调用,而不允许隐式的类型转换发生。

通过使用 explicit 关键字,可以防止一些意外的类型转换,提高代码的清晰性和安全性。它通常用于防止不必要的类型转换,特别是在单参数构造函数可能引起歧义或产生意外结果的情况下。

preprocessor directive

  • #include_next作用是 在寻找头文件时的头文件搜索优先级里,去除该文件所在的当前目录,主要是为C++头文件的重名问题提供一种解决方案。
    • 正确的用法:代码b.cpp想使用 自己拓展修改的stdlib.h, 那么在代码的目录下创建stdlib.h,并在该文件里#include_next "stdlib.h" 防止递归引用。

define、 const、 typedef、 inline

  • define:
    • define是一个预处理器指令,用于创建宏定义。它在编译之前对源代码进行简单的文本替换。可以用来定义常量、函数宏和条件编译等。
    • define的替换是简单的文本替换,没有类型检查和作用域限制。因此,它可能存在一些潜在的问题,如意外的副作用或命名冲突。
    • 例如:#define PI 3.14159,在代码中将PI替换为3.14159。
  • const:
    • const用于声明一个常量,指示标识符的值在程序执行期间不能被修改。
    • const可以用于变量、函数参数、函数返回类型和成员函数。使用const可以提高代码的可读性和安全性。
    • 例如:const int MAX_VALUE = 100;,声明一个名为MAX_VALUE的常量。
  • typedef:
    • typedef用于为数据类型创建别名。它可以用于为复杂的数据类型提供更简洁的名称,增强代码的可读性和可维护性。
    • typedef创建的别名可以像原始类型一样使用,并且不会引入新的类型,只是为已有类型提供了一个新的名称。
    • 例如:typedef int Age;,为int类型创建了一个别名Age。
  • inline:
  • inline用于声明内联函数,它是一种编译器的建议,用于将函数的定义直接插入到调用处,以避免函数调用的开销。
  • 内联函数通常在函数体较小且频繁调用的情况下使用,可以提高程序的执行效率。
  • inline关键字只是给编译器一个提示,编译器可以选择忽略该提示。在大多数情况下,编译器会自动进行内联优化。
  • 例如:inline int add(int a, int b) { return a + b; },声明了一个内联函数add。

  • define主要用于宏定义,const用于声明常量,typedef用于创建类型别名,inline用于内联函数的声明。

#ifndef & #pragma once

为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式。在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别

new & delete

  • new和delete 相对于 malloc/free 分配和释放堆空间。
  • 额外会执行构造函数和析构函数
#include <iostream>

class MyClass {
public:
    MyClass() {
        std::cout << "Constructing MyClass" << std::endl;
    }

    ~MyClass() {
        std::cout << "Destructing MyClass" << std::endl;
    }
};

int main() {
    // 使用new动态分配内存,并调用构造函数
    MyClass* obj = new MyClass();

    // 执行一些操作...

    // 使用delete释放内存,并调用析构函数
    delete obj;

    return 0;
}

namespace

namespace 会影响 typedef 的作用范围,但不会直接限制 #define 宏的作用范围。

头文件

  • 相互引用,前置声明
  • include头文件其实就是将对应的头文件内容贴在include的位置

A.h, B.h 都需要string.h的头文件,然后B.h 会include A.h,那么我在B.h里是不是可以省略include string.h

不应该省略,

  1. 防止代码变更引发的问题: 如果某天 A.h 中移除了 #include ,而 B.h 依赖 A.h 提供的 #include ,那么 B.h 将会因找不到 std::string 而编译失败。因此,显式包含依赖的头文件可以避免这种隐含依赖引发的问题。
  2. 提高可读性和自包含性: 每个头文件应该尽量做到自包含,意思是每个头文件应该独立地包含所有它所需要的头文件。这样做的好处是,任何其他文件都可以安全地单独包含 B.h,而无需额外关心它依赖于哪些头文件。
  3. 减少隐式依赖: 隐式依赖(依赖另一个头文件帮你包含所需的头文件)可能导致维护性问题。显式 #include 可以让代码更具可预测性和可维护性。

include的位置有什么规则和规律吗,头文件和cpp文件前都可以吗?

在编写代码时,往往A.cpp需要include A.h。那A.cpp需要的头文件,我是写在A.cpp里还是A.h里?

  1. 头文件 (A.h):只包含声明所需的头文件,不包含仅在实现中需要的头文件。
  2. 源文件 (A.cpp):包含所有实现需要的头文件,特别是那些仅在实现部分用到的头文件。此外,A.cpp 应该总是包含 A.h。6.

函数的特殊写法

函数传参

  1. 值传递
  2. 引用传递
  3. 指针传递
//值传递
change1(n);
void change1(int n){
    n++;
}

//引用传递,操作地址就是实参地址 ,只是相当于实参的一个别名,在符号表里对应是同一个地址。对它的操作就是对实参的操作
    change2(n);
    void change2(int &n){
        n++;
    }
    //特殊对vector
    void change2(vector<int> &n)
    //特殊对数组
    void change2(int (&n)[1000])

//指针传递,其实是地址的值传递
change3(&n);
void change3(int *n){
    *n=*n+1;
}

引用传递和指针传递的区别:

  • 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
  • 不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
  • 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

指针传递和引用传递的使用情景:

  1. 函数内部修改参数并且希望改动影响调用者。
  2. 当一个函数实际需要返回多个值,而只能显式返回一个值时,可以将另外需要返回的变量以指针/引用传递

闭包、匿名函数

闭包是捕获并持有了外部作用域变量的函数。

闭包(Closure)是指在程序中,函数可以捕捉并记住其作用域(环境)中的变量,即使在函数执行完成后,这些变量依然保存在内存中,并能在后续的函数调用中被使用。闭包的一个重要特性是,它不仅保存了函数本身的逻辑,还“闭合”了函数执行时的上下文环境(即该函数所在的作用域)。

闭包通常用于实现函数内部的状态保持、回调函数等场景。在 C++ 中,闭包通过 lambda 表达式 实现,lambda 表达式可以捕获外部变量并在其内部使用。

例子

auto add = [](int x) {
    return [x](int y) {
        return x + y;
    };
};

auto add5 = add(5);
std::cout << add5(3); // 输出 8
在上面的例子中,add 函数返回了一个闭包,捕获了变量 x 的值。即使 x 在原作用域中不再可用,返回的闭包仍然可以访问并使用 x 的值。

  • 匿名函数是一种没有被绑定标识符的函数
  • lambda 是一种匿名函数
  • lambda 可以表示闭包

匿名函数(lambda)和闭包的关系就如同类和类对象的关系

匿名函数和类的定义都只存在于源码(代码段)中,而闭包和类对象则是在运行时占用内存空间的实体;

类型变参模板

template<typename T>
void swap(T& t1, T& t2)
{
    T temp = t2;
    t2 = t1;
    t1 = temp;
}
swap<int>(a,b);
条件模板类

假设我们有一个模板类 Wrapper,我们希望禁止 VirtualGuardImpl 类型作为模板参数:

template <
    typename T,
    typename U = T,
    typename = typename std::enable_if<!std::is_same<U, VirtualGuardImpl>::value>::type>
class Wrapper {
public:
    void function() {
        // 实现
    }
};

在这个例子中,如果用户尝试创建 Wrapper<VirtualGuardImpl>Wrapper<VirtualGuardImpl, VirtualGuardImpl> 的实例,编译器将报错,因为 std::enable_if 的条件不满足。但如果使用其他类型,比如 int 或自定义类型,就可以正常编译。

这段代码是 C++ 中的一个模板函数或模板类模板参数的定义,它使用了模板默认参数、std::enable_if 条件编译技术以及类型萃取(type traits)。下面是对这段代码的详细解释:

  1. 模板参数 U:

    • typename U = T 定义了一个模板类型参数 U,并给它一个默认值 T。这意味着如果在使用模板时没有指定 U 的话,它将默认使用模板参数 T 的值。
  2. std::enable_if:

    • std::enable_if 是一个条件编译技术,它只在给定的布尔表达式为 true 时启用某个模板。
    • 在这个例子中,std::enable_if 后面的布尔表达式是 !std::is_same<U, VirtualGuardImpl>::value。这意味着只有当 U 不等于 VirtualGuardImpl 类型时,这个模板参数才有效。
  3. typename 关键字:

    • typename 关键字用于告诉编译器 std::enable_if 的结果是一个类型。std::enable_if 返回的是一个类型,如果条件为 true,它返回一个空的类型,否则会导致编译错误。
  4. std::is_same:

    • std::is_same<U, VirtualGuardImpl>::value 是一个编译时检查,用于判断 UVirtualGuardImpl 是否是相同的类型。::value 是类型特征 std::is_same 的一个成员,它是一个布尔值,如果类型相同则为 true,否则为 false
  5. 组合解释:

    • 这段代码的意思是:定义一个模板参数 U,默认值为 T,并且这个模板参数只有在 U 不是 VirtualGuardImpl 类型时才有效。
    • 这是一种常见的模板编程技巧,用于约束模板参数的类型,以确保它们符合特定的要求。

个数变参模板

#include <stdarg.h>
void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。

(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针; (2)然后用VA_START宏初始化变量刚定义的VA_LIST变量; (3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数); (4)最后用VA_END宏结束可变参数的获取。

系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。

int vprintf  / vscanf   (const char * format, va_list ap);                  // 从标准输入/输出格式化字符串 
int vfprintf / vfsacanf (FILE * stream, const char * format, va_list ap);   // 从文件流 
int vsprintf / vsscanf  (char * s, const char * format, va_list ap);        // 从字符串

返回多个数

使用结构体

struct RowAndCol { int row;int col; };

RowAndCol r(string fn) {
    /*...*/
    RowAndCol result;
    result.row = x;
    result.col = y;
    return result;
}

左值与右值

在 C++ 中,左值(lvalue)右值(rvalue) 是两个重要的概念,用来描述表达式的值和内存的关系。它们帮助开发者理解变量的生命周期、赋值和对象管理,特别是在现代 C++ 中引入了右值引用后,优化了移动语义和资源管理。

1. 左值(lvalue)

左值(lvalue,locatable value) 是指在内存中有明确地址、可持久存在的对象,可以对其进行赋值操作。通俗地说,左值是能够取地址的值,可以出现在赋值操作符的左边。

特点:

  • 左值具有持久的内存地址。
  • 左值可以取地址(使用 & 运算符)。
  • 左值通常表示已经存在的变量或对象。

示例

int x = 10;   // x 是左值
int* p = &x;  // 可以取 x 的地址

x = 20;       // 可以对左值进行赋值

在这个例子中,x 是一个左值,因为它表示了内存中的某个对象,并且可以通过赋值语句修改它的值。

2. 右值(rvalue)

右值(rvalue,readable value) 是没有明确地址、临时存在的对象,不能对其进行赋值操作。它们通常是字面值常量或表达式的结果。右值只能出现在赋值操作符的右边,表示一个临时对象或数据。

特点:

  • 右值是临时的,通常会在表达式结束时销毁。
  • 右值不能取地址(即不能使用 & 获取右值的地址)。
  • 右值表示表达式的计算结果或临时对象。

示例

int y = 10;       // 10 是右值
int z = y + 5;    // y + 5 是右值表达式

在这个例子中,10y + 5 是右值,因为它们表示计算出的临时数据,并且不能直接对这些值进行赋值操作。

3. 现代 C++ 中的右值引用(rvalue reference)

C++11 引入了 右值引用,即通过 && 符号表示。这使得右值也能通过引用进行操作,特别是在实现移动语义(move semantics)和避免不必要的拷贝时非常有用。右值引用允许我们通过右值管理资源,避免性能上的损失。

示例:右值引用与移动语义

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = std::move(vec1);  // vec1 资源移动到 vec2

    std::cout << "vec1 size: " << vec1.size() << std::endl;
    std::cout << "vec2 size: " << vec2.size() << std::endl;

    return 0;
}

在这个例子中,std::movevec1 变为一个右值引用,使其内部的资源(如动态分配的内存)直接转移给 vec2,避免了拷贝。

4. 区分左值与右值

通常,左值是表示持久存在的对象,可以通过取地址符 & 获取其地址,而右值是临时的、短暂存在的值,不能直接获取其地址。理解这两者对于编写高效的 C++ 代码和使用现代特性(如右值引用和移动语义)非常重要。

常见误区

  • 字面值常量(如 42、'a')是右值
  • 表达式的结果(如 x + y)通常是右值。
  • 函数返回值若返回的是值,而不是引用,则该返回值是右值。
  • 左值(lvalue) 是可以取地址的值,通常是变量或持久的对象。
  • 右值(rvalue) 是临时值,通常是表达式的结果或字面量。
  • 右值引用(&&)是 C++11 引入的新特性,用来优化资源管理和避免不必要的拷贝操作。

C++11: 花括号初始化列表

使用

在C++98/03中我们只能对普通数组和POD(plain old data,简单来说就是可以用memcpy复制的对象)类型可以使用列表初始化,如下:

//数组的初始化列表: 
int arr[3] = {1,2,3}
//POD类型的初始化列表:
struct A
{
 int x;
 int y;
}a = {1,2};

在C++11中初始化列表被适用性被放大,可以作用于任何类型对象的初始化。如下:

X x1 = X{1,2};
X x2 = {1,2}; // 此处的'='可有可⽆
X x3{1,2};
X* p = new X{1,2};

//列表初始化也可以用在函数的返回值上
std::vector<int> func() {
    return {};
}

变量类型的适用范围

聚合类型可以进行直接列表初始化

聚合类型包括

  1. 普通数组,如int[5],char[],double[]等
  2. 一个类,且满足以下条件:
    1. 没有用户声明的构造函数
    2. 没有用户提供的构造函数(允许显示预置或弃置的构造函数)
    3. 没有私有或保护的非静态数据成员
    4. 没有基类
    5. 没有虚函数
    6. 没有{}和=直接初始化的非静态数据成员
    7. 没有默认成员初始化器

原理

对于一个聚合类型,使用列表初始化相当于使用std::initializer_list对其中的相同类型T的每个元素分别赋值处理,类似下面示例代码;

struct CustomVec {
    std::vector<int> data;
    CustomVec(std::initializer_list<int> list) {
        for (auto iter = list.begin(); iter != list.end(); ++iter) {
            data.push_back(*iter);
        }
    }
};

优势

  1. 方便,且基本上可以替代括号初始化
  2. 可以使用初始化列表接受任意长度
  3. 可以防止类型窄化,避免精度丢失的隐式类型转换

参考文献

  1. https://zh.cppreference.com/

  2. https://leetcode-cn.com/problems/path-with-maximum-gold/solution/huang-jin-kuang-gong-by-leetcode-solutio-f9gg/

  3. https://blog.csdn.net/qq_33221533/article/details/82119031

  4. ⼩贺 C++ ⼋股⽂ PDF 的作者,电⼦书的内容整理于公众号「herongwei」

  5. https://blog.csdn.net/hailong0715/article/details/54018002

6 FPS

卡拉彼丘

  • 信息差:发现分布以及落单对方,灵活跑动隐藏自身,干扰对方准备好时,对方换弹/倒地时补射。
  • 躲避对方多枪线,己方架多枪线,多路线包围
  • 一个位置偷一枪,就换位置。不要再露头。
  • 对枪注意弦化
  • 位置的选择:一要有掩体,二要有安全的退路通道和队友大部队汇合,不要被敌人包夹。
  • 不要急于补人,要观察有没有被敌人包
  • 进阶:时刻预瞄出人点,
    • 弦化靠左墙,预瞄靠左,因为向右出掩体,准星会被向右移动。
    • 学习弹道,反向压枪。
  • 注意不要冲动,以身试陷(除非是突破位)

角色特点

  1. 熊当掩体(带闪光弹,烟雾弹),熊会自动冲锋并结冰
  2. 防守方
  3. 米雪儿:适合压制补枪,技能适合补枪。引诱敌方到背面炮台射程里
  4. 进攻方:
  5. 明:侦察 + 干扰器,风场雷

地图,高空卡墙脚。

  1. 欧拉港口/海湾图:复杂的短距离(掩体之间的距离)小路。适合白墨(带烟雾弹增加自身能力)和熊。白墨攻击走中间,抄底路偷对面的大狙。或者A点上上下下,适合近身跳散弹。
  2. 防守走A
  3. 404基地/巨炮图:白墨可以中路强压。
  4. 防守方 熊,进攻方沙猫无敌B
  5. 88区/古风图,大图远视野,适合大狙,大机枪。还有熊
  6. 禁止白墨。
  7. 风曳镇:大狙和小画家
  8. 防守必选熊(AB滑)和信(传送)
  9. 禁止白墨。

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

Python

装饰器 decorator

@能在最小改变函数的情况下,包装新的功能。1

def use_logging(func):

    def wrapper():
        logging.warn("%s is running" % func.__name__)
        return func()
    return wrapper

@use_logging
def foo():
    print("i am foo")

foo()

Programming Specification

  1. 命名空间(namespace)可以基本理解成每个文件是一个,通过import来使用

if name == "main"

在Python中,if __name__ == "__main__"这种写法通常出现在模块中,它的作用是控制模块的执行流程。

当一个模块被导入时,Python解释器会自动将这个模块的__name__属性设置为模块名称。但是如果模块是被直接运行的,则__name__属性会被设置为字符串__main__。

所以if name == "main"可以用来区分模块是被导入运行还是被直接运行:

如果模块是被导入的,if语句不会执行。因为模块的__name__不等于__main__。 如果模块是被直接运行的,if语句会执行。因为模块的__name__等于__main__。

单下划线、双下划线、头尾双下划线说明:

__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。

_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *

__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

数据快速写入和读取文件

任意变量使用pickle

# 使用二进制
with open('my_dict.json', 'wb') as f: 
    pickle.dump(my_dict, f)
with open('my_dict.json', 'rb') as f:
    loaded_dict = pickle.load(f)

可以序列化的使用json

import json
# 将 dict 保存为 JSON 格式
with open('my_dict.json', 'w') as f:
    json.dump(my_dict, f)

# 加载 dict
with open('my_dict.json', 'r') as f:
    loaded_dict = json.load(f)

多个变量

# 将多个变量组织成字典或列表
data = {
    "scaAvgTime": scaAvgTime,
    "var2": var2,
    "var3": var3
}

result_file = "result.json"

# 将数据写入JSON文件
with open(result_file, "w") as f:
    json.dump(data, f)

# 读取JSON文件
with open(result_file, "r") as f:
    data = json.load(f)

# 获取保存的变量值
scaAvgTime = data["scaAvgTime"]
var2 = data["var2"]
var3 = data["var3"]

python优化 可视化

cProfile + snakeviz + gprof2dot

 ./gprof2dot.py -f pstats Diff.status | dot -Tpng -o ./output/Diff.png

https://github.com/plasma-umass/scalene

reference

https://github.com/jrfonseca/gprof2dot

https://zhuanlan.zhihu.com/p/58535923

https://www.cnblogs.com/oloroso/p/6548189.html

Debug

打印当前堆栈

traceback.print_stack()

icecream for debug

  • 优雅打印对象:函数名,结构体
  • 打印行号和栈(没用输入时
  • 允许嵌套(会将输入传递到输出
  • 允许带颜色ic.format(*args)获得ic打印的文本
  • debug ic.disable()and ic.enable()
  • 允许统一前缀 ic.configureOutput(prefix='Debug | ')
  • 不用每个文件import
from icecream import ic
ic(STH)

from icecream import install
install()

ic.configureOutput(prefix='Debug -> ', outputFunction=yellowPrint)

prefix 添加时间

import datetime
def ic_with_timestamp(*args):
    return '\n\n%s shaojieLog >| ' % datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

ic.configureOutput(prefix=ic_with_timestamp)

hide message

# Disable icecream
ic.disable()

# This message will be hidden
ic("This message will NOT be shown")

# Re-enable icecream
ic.enable()

ic()的输出无法被tee的log文件捕获

这个问题与 icecream 库的 ic() 函数的默认输出机制有关。icecream 默认将输出发送到标准错误(stderr),而 tee 命令的默认行为是只捕获标准输出(stdout)。因此,ic() 的输出不会被 tee 捕获到。

要解决这个问题,你可以采取以下几种方式:

  1. 使用 ic() 输出到标准输出
  2. 你可以配置 icecream 的输出流,使其输出到标准输出,而不是默认的标准错误。这样,tee 就可以捕获 ic() 的输出。
from icecream import ic
import sys

ic.configureOutput(outputFunction=sys.stdout.write)

这样,ic() 的输出就会被发送到标准输出,然后可以被 tee 命令捕获到。

  1. tee 捕获标准错误和标准输出

你也可以让 tee 捕获标准错误(stderr)和标准输出(stdout),这样无需修改 icecream 的配置。

在你的命令中,可以使用如下方式:

python3.8 setup.py build bdist_wheel 2>&1 | tee compile.log

在这个命令中,2>&1 将标准错误重定向到标准输出,因此 tee 可以同时捕获两者。

  1. 使用 tee 捕获标准错误单独输出

如果你只想捕获标准错误的输出,并将其保存到日志文件,可以使用以下命令:

python3.8 setup.py build bdist_wheel 1>&2 | tee compile.log

或将 stderrstdout 单独重定向:

python3.8 setup.py build bdist_wheel 2>compile.log

虚拟环境venv

python3 -m venv name

#在Windows上,运行:
name\Scripts\activate.bat # poweshell运行activate.ps1
#在Unix或MacOS上,运行:
source name/bin/activate
#(这个脚本是为bash shell编写的。如果你使用 csh 或 fish shell,你应该改用 activate.csh 或 activate.fish 脚本。)
python3 setup.py install

各种依赖

pip freeze >requirements.txt //导出
pip install -r requirements.txt //安装

pip换源

有时候开代理会出现Retry

vim ~/.pip/pip.conf 
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

pip config set global.trusted-host pypi.mirrors.ustc.edu.cn  
pip install --trusted-host mirrors.bfsu.edu.cn icecream  

python的实现过的各种功能模块

并行调用shell命令,超时kill

https://github.com/Kirrito-k423/BHive-Prediction-Compare/blob/main/pythonTest/0326_newBar_qcjiang.py

基于Pipe的自定义多进程进度条

https://github.com/Kirrito-k423/BHive-Prediction-Compare/blob/main/pythonTest/0326_newBar_qcjiang.py

为什么c语言运行比python快

运行流程区别

python的传统运行执行模式:录入的源代码转换为字节码,之后字节码在python虚拟机中运行。代码自动被编译,之后再解释成机器码在CPU中执行。

c编译器直接把c源代码编译成机器码。过程比python执行过程少了字节码生成和虚拟机执行字节码过程。所以自然比python快。

解释性语言

解释型语言没有严格编译汇编过程,由解释器将代码块按需要变运行边翻译给机器执行。因此解释型语言一度存在运行效率底,重复解释的问题。但是通过对解释器的优化!可以提高解释型语言的运行效率。

Python 字节码

Python 以 .pyc 结尾的 “ 字节码(bytecode)” 文件(二进制文件),一般位于__pycache__ 的子目录中,可以避免每次运行 Python 时去重新解析源代码。

python -m py_compile file.py  # 生成单个pyc文件

python程序运行中的 Python 字节码 是什么时候产生的,我修改py文件,其对应的字节码文件会在何时更新

gpt3.5: Python字节码是由Python解释器在执行Python源代码之前生成的中间表示形式。它是将源代码翻译为机器可以理解的指令序列的一种形式。字节码文件的扩展名通常为.pyc(Python 3)或.pyo(Python 2)。

当你运行Python程序时,如果存在对应的字节码文件(.pyc或.pyo),解释器会首先检查字节码文件的时间戳。如果字节码文件的时间戳比源代码文件的时间戳更晚,且没有进行代码的修改,解释器会直接加载和执行字节码,跳过源代码的编译过程。

当你修改了Python源代码文件时,字节码文件不会立即更新。Python解释器会在下一次运行程序时,检测到源代码文件的修改,并重新编译生成新的字节码文件。这样,更新后的字节码文件将反映源代码的更改,并用于后续的执行。

访问和理解 Python 字节码

经过编译的python文件可以提高程序的运行速度,一定程度上也对源代码起到了保护作用。然而如果我们只有编译过的python字节码文件,就给我们审查源码造成了一定的困难,这就引出了python字节码反编译的需求。

如果你想玩转字节码,那么,Python 标准库中的 dis 模块将对你有非常大的帮助;dis 模块为 Python 字节码提供了一个 “反汇编”,它可以让你更容易地得到一个人类可读的版本,以及查找各种字节码指令。

知道如何去访问和阅读 Python 字节码将让你很容易回答为什么某些结构比其它结构运行的更快这样的问题(比如,为什么 {} 比 dict() 快)(尝试对比一下: dis.dis("{}") 与 dis.dis("dict()") 就会明白)。

pyo优化文件

pyo文件是源代码文件经过优化编译后生成的文件,是pyc文件的优化版本。编译时需要使用-O和-OO选项来生成pyo文件。在Python3.5之后,不再使用.pyo文件名,而是生成文件名类似“test.opt-n.pyc的文件。

python -O -m py_compile test.py

Python 虚拟机

CPython 使用一个基于栈的虚拟机。(你可以 “推入” 一个东西到栈 “顶”,或者,从栈 “顶” 上 “弹出” 一个东西来)。

CPython 使用三种类型的栈:

  1. 调用栈(call stack)。这是运行 Python 程序的主要结构。它为每个当前活动的函数调用使用了一个东西 —— “ 帧(frame)”
  2. 在每个帧中,有一个 计算栈(evaluation stack)(也称为 数据栈(data stack))。这个栈就是 Python 函数运行的地方,运行的 Python 代码大多数是由推入到这个栈中的东西组成的,操作它们,然后在返回后销毁它们。
  3. 在每个帧中,还有一个块栈(block stack)。它被 Python 用于去跟踪某些类型的控制结构:循环、try / except 块、以及 with 块,全部推入到块栈中,当你退出这些控制结构时,块栈被销毁。

Python 如何工作

Python 与大多数解释型语言一样,确实是将源代码编译为一组虚拟机指令,并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

在了解c语言编译流程的时候,联想到了python有什么不同。

参考文献

https://zhuanlan.zhihu.com/p/39259061

Scons

Scons

  • SCons is a software construction tool that can be used as an alternative to traditional build systems like Make and CMake.
  • It is a Python-based build tool that provides a convenient and flexible way to define and manage the build process for software projects, including C++ programs.

Scons VS cmake

  1. 基于python语言的构建工具,对开发者来说过度自然,简单,no need to learn domain-specific language like cmake

其余cmake有的, Scons 也有。

  1. cross-paltform,
  2. SCons has built-in support for dynamic dependency analysis, meaning it can automatically detect changes in source files and rebuild only what's necessary. This can result in faster builds for large projects.

Project structure

  1. Sconstruct python file as compile entry

framework grammar

  1. add option for scons command
AddOption('--buildDir', 
   dest='buildDir', 
   type='string', 
   default="build/", 
   # default=False,
   nargs=1, 
   action='store', # meaning save the string
   # or action='store', meaning True or false
   metavar='DIR', 
   help='Base build directory'
)
baseBuildDir = GetOption('buildDir') 
  1. add sub scons config file and build result path using variant_dir
env.SConscript("src/SConscript", variant_dir=buildDir, exports= {'env' : env.Clone()})     
  1. achive debug mode

using scons debug=1 command.

env = Environment()
debug = ARGUMENTS.get("debug", 0)
if int(debug):
   print "in debug mode"

main construct grammar

  1. Define the Build Environment: In the SConstruct file, define the build environment by creating an Environment object. You can specify compiler options, flags, include paths, library paths, and other build settings within this object.
env = Environment(CXX='g++', CCFLAGS=['-O2', '-Wall'], CPPPATH=['include'], LIBPATH=['lib'])
 libEnv = env.Clone()
  1. Specify Source Files and Targets: Define the source files for your C++ program and specify the target(s) you want to build using the Program() function.
source_files = ['main.cpp', 'util.cpp', 'other.cpp']
# or select the src files 
Object('hello.cpp')
program = env.Program(target='my_program', source=source_files)

In this example, main.cpp, util.cpp, and other.cpp are the source files, and my_program is the name of the target executable.

  1. static or dynamic lib
# static
Library("t", Glob("src/*.cpp"))
# dynamic
source = Glob("src/*.cpp")
SharedLibrary("t", source)
Program(["hello.cpp"], LIBS=["t"], LIBPATH=".")
  1. execute command during compilation

  2. this is usually to print info

  3. The command is executed when any of the specified dependencies (allSrcs, ".git/index", or "SConstruct") change.
env.Command(
 target='bar.out',
 source='bar.in',
 action=["rm -f $TARGET", "$BAR_BUILD < $SOURCES > $TARGET"],
 ENV={'PATH': '/usr/local/bin/'},
)
env.Command(
   versionFile, 
   allSrcs + [".git/index" "SConstruct"],                                                 
   'printf "#define ZSIM_BUILDDATE \\"`date "+%Y-%m-%d %T"`\\"\\n#define ZSIM_BUILDVERSION \\"`python misc/getver.py`\\"" >>' + versionFile) 

Command

scons -c  # Clean
scons debug=1    # Rebuild using `SConstruct` file in debug mode

scons-project analysis

TODO: multipim how to add a singel head file during compilation process.

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

https://scons.org/doc/production/PDF/scons-man.pdf

LinuxFolderInstall

system folders structure

根据教程

  1. /etc:是 Etcetera(等等) 的缩写,这个目录用来存放所有的系统管理所需要的配置文件和子目录。
  2. 这个是系统中的配置文件,如果你更改了该目录下的某个文件可能会导致系统不能启动。各种服务(ssh,apache2,nfs)的配置文件
  3. /lib:是 Library(库) 的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库。
  4. /opt:是 optional(可选) 的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的。
  5. /usr:是 unix shared resources(共享资源) 的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录。It's install for all user.
  6. /var:是 variable(变量) 的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件

sudo install path

TODO: during the application install, which locations those app used?

I guess it's usr/bin or /include , opt and /lib

  1. GNU G++
  2. cuda
  3. intel one-api

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

3.3 EfficientWorkLearning

科研工作的目标

  1. 从底层的优化做起,自底向上的。对整个AI训练的难点有个全面细致的认知。
  2. 或者从应用的问题出发建模,从上到下有个全面的认知。
  3. 往架构师的方向努力

淡而不厌,简而文,温而理,知远之近,知风之自,知微之显,可与人德矣。

科研学习

狠狠吸收

华为实习部门的都是手握A会的博士大佬。本人望尘莫及,我会狠狠吸收的。

科研的长远与犀利的眼光

  1. 如何识别伪装信息 和被包装的工作
  2. 明确理论目标上限,当前的差距,实现路径

研究理解与实现

  1. 跨领域知识:公众号,订阅
  2. follow前沿论文:follow学者, 公众号,
  3. 实际问题、需求的发现
  4. 技术论证:理论上限,可行方案
  5. 独立任务分割
  6. 高效实现(解决问题)

科研工作的全局观念

  • 自顶向下的设计规划、工作全局观 (从目标、需求、愿景出发。不断细化实现点)
  • 顶:论文全流程思路图(构思与其余工作的对比):当前实现和问题、兼顾创新性的方法 和 设计目标期望效果。
  • 中:代码实现逻辑框架图
  • 底:代码语言具体实现:高内聚低耦合的重要性,解耦,拆分,这样就容易重构了。独立的微服务
  • 自底向上的知识积累 与研究方法提出
  • 底:领域的基础知识
  • 中:领域的主流方法和解决方案
  • 顶:行业痛点和有待补完的领域空白。
  • 当两者相联,目标才能顺利的达成,

高效学习的过程中注意点

  1. 学习的优先级:用20%时间先掌握80%的基础知识或者感兴趣的关键
    1. 难的问题可以讨论合作得出
  2. 提问式主动学习:不是被动学习,尝试通过提问、讨论、教授他人等方式来加深理解和巩固所学内容。
  3. 合作学习: 不仅能头脑风暴idea。对概念的理解,表达能力,心理健康有好处
  4. 交叉与分割学习: 概念文字、视频和案例分析交叉理解。长时间执行单一学习会枯燥,效率降低。切换学习一些新鲜东西:每日关注LLM的有趣实现。
  5. 理论实践交融:实际运行或者编写测试代码运行来深入理解
  6. 持续反馈与评估:每天每周对学习的进度和效果进行分析、来调整学习计划和研究方向。可以遵循STAR 法则。

具体研究点的克服

体系结构量化分析方法,重点就在于量化分析开销,比较然后进行tradeoff。当前前提是你要有基本的相关概念。

具体知识来源的优先级,或者说如何使用搜索引擎:

  1. 明白原理,设计实验,实际机器测量
  2. 认知概念,理解 (图解 >> 列表对比 >> 文字list >> 大段描述)
  3. 阅读相关的论文以及书籍
  4. 国内大佬的博客和大论文
  5. 国外论坛Stack Overflow > 国内知乎 > 博客园 > csdn > 其他
  6. 资料的来源(论文 >> 官方文档 >> 英文博客 >> 高质量中文资料)

在理解概念,量化了具体场景的数值后,就可以开心进行tradeoff了。

  1. 思维导图、摘要,来理清概念 和思路
  2. 结合PPT 数据与图表展示效果

注意项目的可读性和可拓展性一般与性能是不兼容的。这取决于项目的checkpoint/middleValue的保存,在性能优化时往往会消除中间变量。这样会导致代码的可读性和可拓展性下降。

check-point的合理设置

  1. 合理的检查点,既是阶段性的成果,又能在此衍生出无限的可能
  2. 需要能高效的复现与重构

关于如何解决困难

困难的定义可以基于以下几个要素进行评估:

  1. 个人技能能力:困难的程度可以取决于个人所具备的技能和能力水平。对于一个人来说,某项任务可能很容易,而对另一个人来说可能很困难,这取决于他们的专业知识、经验和技能。如果一个人已经具备了必要的知识和技能,那么他们可能更容易应对困难任务。相反,如果缺乏必要的知识和技能,任务就会更具挑战性。
  2. 任务量评估:任务的规模和复杂性也是评估困难程度的重要因素。任务量的多少以及任务本身的复杂性(比如需要解决的问题、涉及的步骤等)会对困难程度产生影响。
  3. 多人合作:效率会由于沟通同步而减半
  4. 量化分析加深理解:对于某些任务,特别是涉及复杂问题解决或决策制定的情况,进行量化分析可以加深对问题本质的理解。这种理解的深度也会对困难程度产生影响,因为解决关键核心会对整个任务的理解的评估进行重大修正。
  5. 对未知领域的任务量评估,会随着了解而变得准确。(这不是产品经理的工作吗?
  6. 时间的紧迫程度:完成任务所要求的时间紧迫程度也是评估困难程度的因素之一。如果任务需要在很短的时间内完成,那么它可能会被认为是更具挑战性和困难的。

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

3.2 taskPriority

工作优先级四象限(优先级矩阵)

  • 基础版本(艾森豪威尔)
    • 对于紧急又重要的事情马上做。如果这类事情过多,那就想办法规划时间,减少此类事情。
    • 对于重要但不紧急的事情计划做。尽可能地把时间花在重要但不紧急的事情上,这样才能减少产生重要且紧急的工作量。
    • 对于紧急但不重要的事情授权做。处理原则是授权,让别人去做。
    • 最后对于不重要不紧急的事情减少做
  • 额外的维度
    • 依赖关系:工作中显露的潜在工作会打断工作的交付,砍半降低交付效率
      • 尽可能全面

拓展版本

  • 当前工作优先级评估由 四个连续值维度 + 三个逻辑指标 组成
  • 优先级评估的时候不止是自己的视角,还有别人的视角(别人在心里的权重 * 重要性 * 紧迫性)。其中别人在心里的权重,一般来说: 父母、爱人、子女 > 领导 > 我
四个连续值维度
  • 喜好程度
  • 估计工作量(投入收益比)。这一点其实很难量化,自己都没有做怎么知道,只能横向收集友商的数据。
  • 紧急的纬度由DDL时间确定,这点可以和工作量指标互动。
  • 重要性由以下几点确定,都能提高对工作的重要性评价:
    • 增加对工作的喜爱程度的任务: 高效插件与可视化工具的学习使用,
    • 提高工作效率的任务:学习基础知识,
    • 减少长期的工作量:学习、制造和使用轮子;自动化工作。
三个逻辑指标
  • 工作间依赖关系
  • 专注度要求(与疲劳度互补,清醒时才能做思考工作,一天工作后也能进行的简单工程工作)
  • 是否属于未知的领域。(与专注度要求不是正交的关系,是集合的包含关系。需要动脑的事情,肯定是未知的)
经常遇到的实际情况

相同的指标

  1. 紧急程度:不紧急。我一般会比较焦虑,所以工作会较早立项。
  2. 重要程度:我认为重要的才会主动去做,无论是对眼前的毕业考核,还是长远的考虑
  3. 喜好程度:我认为有趣的才会主动去做
  4. 工作间的依赖关系:我会遵守逻辑

不同的指标:

  1. 是否未知:阅读信息的需求
  2. 是否需要专注: 思考需求

两者结合:纯思考 > 阅读加稍微思考 > 初步的阅读收集信息 > 纯机械工作

任务周期内:时间分配和执行顺序

之前的任务优先级评判,都是从完成任务的角度考虑。但是实际情况是每个任务都需要很久(许多任务周期)才能完成。

按照优先级的指标,例如:

紧急性(3) 重要性(3) 喜好(1) 工作量(3) 总分 分配 要求
report 3 0 0 0 3 一天欠 2
thesis 3 3 0 3 9 两天多 3
AI 2 2 1 2 7 两天欠 1
OpenCL 2 1 1 1 5 一天多 1
web 1 0 0 1 2 一天欠 1
Summary 26
  1. 紧急性: 迫在眉睫(几天), 稍等几周,稍等几月,半年一年,可有可无
  2. 重要性: (当下)重大转折,(潜在)深远影响, 一年内小方向,与我无瓜
  3. 喜好:特别喜欢,有点意思,毫无波澜,有点厌恶
  4. 预估工作量(专心情况下):半年以上,一个季度,一个月,一周
  5. 要求(专注度):纯思考 > 阅读加稍微思考 > 初步的阅读收集信息 > 纯机械工作 (3~0)

注意

  • 工作安排 “必须做”占 40%,“愿意做”限制在 30% 左右,剩下30%处理出现的未发现的依赖任务和计划外工作。
  • 涉及到合作的工作:要与对方商量好,自己的选择(为什么把你鸽了,不是)

理想中的二维可视化细节

  • 科研工作与生活各自独立一张图。处理的时间段不同。
  • 横坐标是时间DDL表示紧急程度Urgency,纵坐标是重要性Impact(代表能增强自身和造轮子,还是繁琐小事)
    • 横坐标会随时间自动移动,
    • 标记出四块或者9块颜色
  • 节点可以可视化的部分
    • 颜色深浅表示喜好程度、投入收益比
    • 大小表示工作量绝对值(难易程度)
    • 会根据每日的任务自动调整
    • 甘特图 Gantt:的长条状,中间塞进度条的百分比实现。
    • 和连线表示工作依赖关系
    • 特殊颜色/形状 表示设置里程碑(北极星)任务,完成后自己会收获什么(能力属性标签)
  • 节点额外的属性值(不可视化)
    • 任务的风险
    • 需要的合作者,资源
    • DoD (完成标准,验收标准)
  • 根据公式和数据, 计算工作的优先级并给出推荐。
    • 考虑WIP(Work in Progress)
  • 实现日历功能
  • 为了能激励自身,引入信息增长统计
    • 过去一周/月/季度/年,完成的各类型的Task
    • 引入勤劳值(工作量统计),和收获值(能力增长统计)
    • 能力属性标签, 数值是否随时间衰减

已有的优先级矩阵产品

  • ducalis
  • 另一种维度,将紧急程度与工作量交换:pic

团队合作的优先级

团队合作中,解决问题的策略与优先级

对象:领导、部门的同事团队( 其余部门的同事团队),个人主体。

思考的基础与前提(多沟通,深分析,找关键):

  1. 找到问题的关键,并提出实用有效的方法
  2. 问题考虑全面,目光长远,设计方法可持续

情形:

  1. 别人遇到问题求助
    1. 授人以鱼不如授人以渔
    2. 如果有其余需求,归纳到最后一点统计决策
  2. 自己遇到问题
    1. 研究瓶颈
      1. 在充分的调研与汇总整理后,向同事或者上级咨询与求助
    2. 两难抉择: 返工的bug修复,新功能,新业务,新研究方向与现有的工作的时间冲突
      1. 工作优先级四象限:根据重要性、紧急程度、喜好程度、工作量(投入收益比)与依赖关系分类
      2. 要与提出需求的对方商量好,解释自己的选择和困难

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。