一些我的 Vim&tmux 配置备忘
注:由于配置又杂,又有很多的来源早找不到了。如果你发现有来自于你的配置但是没有提到,在下面回复一下让我加上就好,阿里嘎多!
前言
有笨蛋在每次准备继续配置 Vim 和 tmux 时,打开自己几个月之前刚该国的配置都会一脸懵……于是在此做个备忘。这并不是一个教程,嗯。
以及首先需要承认我是个 VSC 人,所以以下的 Vim 配置更多的是在 VSC 没法用时做一个替代,并没有完全的美化和配置舒服。但是目前够用了,大概?qw
一个好处是,要是遇上点什么没法装 VSC 的服务器或者小板子,只要有个 ssh 连接,就一个 sftp 丢上去这一套就行 qwq
Vim
先来个展示:
(如果你发现配置文件里有什么有的但我又没提到的,那说明……我也忘了(扶额)
基础设置
1234567891011121314151617181920212223set nocompatiblefiletype onfiletype indent onfiletype plugin onsyntax onset encoding=utf-8set spellset numberset cursorlineset tabst ...
来使用Worker做免费的Email服务器!
前言
由于现在用的自定域名服务商不给开IMAP/SMTP~~(说的就是你!zoho)~~,而市面上其它的服务商要么需要钱钱,要么只给收信……在这样的条件下,很早就想要自己搭建一个邮件服务器了。但因为自己服务器上奇奇怪怪的问题一直懒得解决,就一直拖着。
而自从Cloudflare推出了它们的邮件路由之后,很多人就开始用它转发邮件。但此时的Email Worker大多数还只停留在只能收信->筛选->转发的阶段。而如果你想用Worker发信呢?对不起!用第三方API吧。
直到不知道什么时候,Cloudflare突然给Email Routing加上了发信的能力(有多突然呢?它自己的API文档都还没更新,types也有问题)。在发现了这一点之后,我就开始思索能否用它的Worker来做一个完整的邮件服务器,包括收发信的能力,而非只是转发到自己的邮箱。
Email Routing 和 Email Worker
这是Cloudflare不知何时推出出来的服务。本质上就是让Worker支持了SMTP的服务,并添加了MX记录到cloudflare的服务器。
官方支持了它可以实现回信和向前转发的 ...
来谈谈64位乘法器和除法吧!
前言
在开始之前,我们必须要先谈谈我们的目标:
我们在这里并不是想完成一个大作业或者写出一个很好的乘法器,而是在你上完一天课后,在睡前的两小时内能完成的的一个作品。
所以,我并不会做出一个很好的乘法器,我们将会使用一些更简单的方式。
当然我知道,你肯定不会满足于此对吧?所以我们仍会谈一谈更快速乘法器的原理,并给出一点示例。
请一直记住这点吧:我们想要一个简单玩意,并尽可能的从中理解它的原理。
对了……你可能会发现,越往后面的内容其实越简单哦。所以实在不会的话,不要死磕哦w
那么w,让我们开始吧喵!
阵列乘法器
或许你已经学过计算机组成原理,并且脑子里已经充满了每次移位相加的东西(或者补码两位乘之类的)。
但是,还是让我们来看看吧。
我们不妨先从4位*4位的乘法开始:
对于以下的一个乘法:
$ 1011 * 0111 $
它是这么运算的:(希望格式是对的)
1234 1011 1+ 1011 1+ 1011 1+ 0000 0
(想一想10进制时,你是怎么做乘法的?)
它需要四个加法。我们可以这么做:(计组里为了节 ...
创建一个64位加法器!
前言
由于这个学期选了一节硬件设计的课程,所以开始写一些硬件的小东西w
所以不妨从一个最核心也比较简单的部件:加法器开始?
我默认你对二进制已经很熟悉惹。不熟悉的话,可以去看一些进制相关的内容?
全加器
如果你对这些内容已经很熟悉的话,跳转到相应的区域吧!
半加器
要想谈论更多位的加法器,我们不妨先来看看一位得到加法器是怎么构成的w
不妨设其输入的两个值为A和B,输出S和进位C(正如你10进制下单位的加法也会有进位一样!)
或许你会想到画一个真值表,但……我们不妨直接来想想吧。
什么时候S会为1呢?当A和B同时为1时?不是,因为此时进位了,S为0。A和B同时为0呢?也不行,0+0=0。也就是说,当且仅当A和B中只有一个为1时,S才为1。也就是如下表示:
1S=(A&!B)|(!A&B);
在这里,我们不妨约定下记号。和C语言中类似,&代表按位与,|代表按位或,!代表按位非,^代表按位异或。注意里面并没有同或,当我们必须用到时使用!(A^B)代替。
由于有公式:(A&!B)|(!A&B) == (A^B),上面的代码更好写为:
1S=A^B;
类似 ...
关于Whitebox GAN的一些碎碎念
什么是Whitebox GAN?
Whitebox GAN网络最初发表于CVPR2020的论文Learning to Cartoonize Using White-box Cartoon Representations。其是一个将现实风格的图片(视频)转换为动漫风格的网络。
该网络改进了生成图片中的高频纹理和细节,获得了更好的图片动漫风格化的结果。
其代码开源在GitHub,可以下载已经训练完成的代码进行尝试~
该网络同样在B站上有效果展示!
网络结构
该网络采用了Generater-Discriminator结构,通过一个Generator网络实现从现实图片到动漫图片的风格域转换;同时,采用了两个Discriminator来进行甄别和训练。
Generator
Generator网络采用了一个标准的结构:三层down sample layer(下采样层),四层residual block(残差网络)和三层up sample layer(上采样层)。其中,从down sample layer到对应的up sample layer之间有对应的skip connection(跳跃连接),以 ...
堆
简介
有一棵树,其树上的每个节点有一个值,且每个节点的这个值都大于等于(小于等于)其父亲上的值。
那么,我们就把这颗特别的树叫做一个“堆”。
如果,节点值是大于等于其父亲的值,那么我们就叫做小根堆;反之节点值小于等于其父亲的值,那么我们就叫做大根堆。
这是一个小根堆
这也是堆(一个大根堆
对于一个基本的堆,它可以支持:插入一个元素,输出最大(小)值,删除最大(小)值。
如以上就是C++ STL中堆的操作。
堆有很多种类,如对顶堆、斐波那契堆……但在这篇博客中,让我们关注一个最基本的堆:二叉堆。
二叉堆
对于二叉堆而言,它是一颗二叉树。
但是二叉树并不够好。正如上面第二个堆,完全退化成了一条链。对此,我们还希望它是一个完全二叉树。
当然了,它同样需要具有堆的性质!
每个节点的这个值都大于等于(小于等于)其父亲上的值
而对于这颗二叉树而言,树根就是它最大(最小)的元素!
为了方便,接下来都会是一个大根堆
还记得吗?对于一个堆,它需要有一些基本的操作:插入一个元素,输出最大值,删除最大值。让我们来一个个的解决吧。
姆好吧……或许在这之前,我们先来看一看怎么存储一颗二叉树吧!
存储
...
关于符号链接的一些碎碎念
静态链接
在C中,编译一个程序的过程如下:
xx.c->(翻译器)->xx.o->(链接器)->xx
而在第二部将xx.o构造为一个可执行文件的过程被称为静态链接
为了完成静态链接这个目标,链接器需要做两件事:
知道每一个变量到底是什么,这样才能将变量的定义与引用相关联
这里的变量可以是一个全局变量,一个静态变量,一个函数……
而在之后,统一将这些变量的定义和引用称为符号
这一步被称为符号解析
知道每一个变量在哪,这样才能将符号和内存地址相关联,并将所有的符号修改为内存地址
这一步被称为重定位
而诸如extern、static、attribute(weak)这些关键字,则正是在符号解析中发挥作用的
可重定位目标文件
下表是一个典型的可重定位目标文件:
段
作用
.text
已编译的机器代码(此时符号未被替换)
.rodata
只读数据
.data
已初始化的全局和静态变量
.bss
未初始化的全局和静态变量
.symtab
符号表(也就是我们要关注的部分)
.rel.text
.text重定位信息
.rel.data
. ...
在C中面向对象:#0x2 让我们来实现一个迭代器!
非常建议先看0x1
说起来我才发现,因为我超喜欢用波浪线,一大堆东西被替换成了删除线QAQ
前言
我们先来解决上一节中遗留下来的几个问题吧
UNUSED
由于在上一节中,我们强行规定了函数该长什么样。但是,有些时候我们可能并用不到某些参数,这个时候编译器就会报warning或error(取决你有没有开Wall、Werror、Wextra)。
为了保证编译器既不会报错,又能符合固定的函数原型,在此我们需要定义UNUSED宏。
12345678#ifdef UNUSED#elif defined(__GNUC__) || defined(MSVC)#define UNUSED(x) UNUSED_##x __attribute__((unused))#elif defined(__LCLINT__)#define UNUSED(x) (void *)(x)#else#deifne UNUSED(x)(void *)(x)#endif
该宏的作用是:若编译器有__attribute__((unused))选项时,则给该变量添加上unused属性,并重命名为UNUSED_var。
其示例用法如 ...
在C中面向对象:#0x1 来"注册"一个对象吧~
非常建议先看#0x0 w~
目标
在这一节中,我们希望能够实现类似C++中一样,能一键new和delete一个对象。
同时,我们也希望能构造一个通用的“类”模板,以便规范我们的编写和调用。
对此,我们需要:
搞清楚一个类的原型需要些什么
实现在程序中“注册”一个“类”
成功new一个对象
实现一系列的函数,以便代替操作符进行一个统一的调用
那么,让我们开始吧~
一个类的原型
为了让所有的类看起来相似,同时也是为了更方便的注册一个类,我们需要首先规定一个类必须要存储哪些信息。
对此,我们不妨先来一个结构体存吧~
123typedef struct CLASS_T{} class;
首先,我们需要知道如果要新建一个对象的话,需要多少的空间。也就是说,我们需要存储一个类的大小。
于是我们加上const size_t type_size;
接下来,为了能统一所有类的构建,我们并不希望生成一个对象的时候,都要去调用这个类的构造函数(如你要一个cat对象,就要调用cat_constructor;一个dog对象就要dog_constructor)。
我们期望的是像C++那样, ...
在C中面向对象:#0x0 封装、继承与多态
前言:为什么要在C中面向对象
虽然c++由c语言发展而来,且其中(大部分)兼容了c的语法。它解决了c中开发繁杂(没有对象、抽象方法),不好阅读(为了实现多态,指针、强制类型转换满天飞),不易维护等痛点。
但不得不说,现在的c++更像一锅大杂烩,学习难度指数级上升。而c与其相比就变得很容易入门了(基础总共就那么点)。而且,很多的嵌入式项目并没有提供c++的工具链,导致仍然不得不使用c编程 (或者折腾一周环境之后,回到用c编程)
当然……以上其实并没有完全说明为什么要在c中面向对象。毕竟要实现的话,又繁琐又不方便……
但是它很有挑战不是喵!而且还可以学到一些新的技巧。
什么是面向对象编程
对于一个程序,可以分为两部分:
数据(你希望处理的东西)
算法(如何处理这些数据)
面向过程编程
C就是一个典型的面向过程的语言。它的数据和算法是分开的,你通过将数据一个一个放到函数里进行处理,获得想要的结果。
面向对象编程
面向对象就是将数据和算法包在一起,做成一个东西。接下来无论你想要做什么(无论是改变参数还是产生行为),你都直接告诉这个东西就好
想要让一个语言能够面向对象,一般需要实现三个特征: ...