本文介绍Windows平台上命令行开发相关工具,由于涉及软件众多,只做简介,不去深究。

1. 原生工具

Windows下有三个命令行工具:Command Prompt(cmd)、PowerShell和WSL Bash。

cmd历史悠久,虽然有诸多不足,但胜在启动快,各种命令也比较熟悉。

PowerShell功能强大,目前发展良好,但是启动偏慢,而且许多命令变化较大。

WSL Bash暂未用过,有文章说它有性能问题,但是我估计make和find这种初级应用应该没有影响,最大困难是要启动WSL,硬盘空间吃不消。

综合下来,还是cmd最常用。

2. 扩展工具

cmd很难配置。更改默认字体异常困难,唯一可用的是等距更纱黑体,效果也一般, 字体的宽度问题还会导致一些DOS窗口绘图出现偏差。更改主题颜色就更是难以实现,因为它不支持256色。

市面上已经有丰富的扩展工具。

(1)ConEmu

这是我每天在使用的工具,所以放在第一个介绍。

它相当于一个cmd的外壳,提供了外观美化、窗口管理、快捷键等多方面的增强。使用它能够很轻松的实现多个cmd平铺展开。

(2)cmder

它打包了ConEmu,FAR Manager,Clink等多个优秀工具,界面美观,功能强大,实现了一站式的cmd增强替代方案。 但是启动速度稍慢。

(3)Alacritty

它是Rust语言写的工具,Rust编的工具通常都很快,并且使用了GPU加速,显示效果上比较细腻。 现在还处于项目早期,感觉功能有限。

(4)Console2, ConsoleZ

早年间Console2是一个知名的cmd外壳,后来停止更新,ConsoleZ是它的继任者。

(5)Terminus, Hyper

这两个都是Web技术(Node.js)实现的工具,界面异常美观。追求炫酷的用户,它们非常适合。

(1)-(5)这些工具都只是一个外壳,后台可以调用cmd,powershell或bash等各种Shell。

(6)msys2, mingw, git-bash

它们都实现了一个小型Linux操作环境,可以获得类似Linux的使用体验。安装后会获得一个命令行窗口,后台调用bash。从我的使用体验上讲,bash的操作体验要优于cmd,但是又说不清哪里好。

(7)cygwin

cygwin是msys/mingw类似的工具套件,安装后也会获得有一个bash。

(8)MobaXTerm

它是一个基于cygwin的终端,功能很多,甚至包含一堆DOS游戏 😂,其中最让我心仪的是它支持串口通信!可以一边make程序,一边观察串口输出。

(9)Babun

它也是基于cygwin的一个工具套件,功能很丰富,但是已经停止更新几年了,作者在官网上很幽怨的说大家只想拿来用,现在想转手项目却找不到人。

(6)-(9)这些工具都是基于bash+mintty,彻底脱离了cmd。开发过程中用到的命令行工具,一部分兼容二者,另一些只在一种上好使。从开发角度,系统里安装一个msys2或cygwin总是必要的。

(10) vim, emacs, sublime_text, vscode

这几个工具自己内置shell,或通过扩展添加一个内部shell,当需要处理大量代码文件时候,在编辑器中开个shell更方便,避免来回跳转。

3. 辅助工具

我们使用命令行的时候常用操作可以总结为:

  • 目录的创建、查看、跳转、删除、复制、重命名、搜索
  • 文本的创建、查看、编辑、删除、复制、重命名、搜索
  • 文本内容搜索
  • 查看系统信息
mkdir/md创建文件夹
rm/del/rmdir删除文件、文件夹
cd目录跳转
dir/ls打印文件(夹)列表
find搜索文件、文件夹
grep搜索文件内容
diff/fc比较文件内容
echo/cat打印和读取
where/which获取某命令路径
cp/mv/ren复制、移动、重命名
path/env打印环境变量

我们在Windows上的大多数操作,都可以简化成这些命令或其组合。

以上命令中,有些是Windows命令,比如where,有些是Linux命令,比如为which,如果我们安装配置了msys2,则可以通用。

推荐安装一些辅助工具来提供工作效率,它们是:

  • clink:自动补全命令
  • far:资源管理器
  • fd:find增强版
  • fzf:find增强版,但是与fd用途不同
  • rg/ag:grep增强版
  • vim/gvim:无需赘言

其中clink一定要安装,没有clink的cmd是没有灵魂的。

4. 右键菜单

假如你也选择ConEmu,安装配置好以后,最好添加一个右键菜单“Open ConEmu Here”,这样就可以在当前文件夹打开ConEmu。

可以通过修改注册表完成。

(1)选中文件夹的右键菜单

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\ConEmu Here]
@="Open ConEmu"
"Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0"

[HKEY_CLASSES_ROOT\Directory\shell\ConEmu Here\command]
@="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -dir \"%1\" -run {cmd} -cur_console:n"

(2)文件夹空白处的右键菜单

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\ConEmu Here]
@="Open ConEmu"
"Icon"="C:\\Program Files\\ConEmu\\ConEmu64.exe,0"
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Directory\Background\shell\ConEmu Here\command]
@="\"C:\\Program Files\\ConEmu\\ConEmu64.exe\" -here -dir \"%V\" -run {cmd} -cur_console:n"

(完)

使用SEGGER Embedded Studio越来越多,本文总结了一些有用的小技巧。
本文是对SEGGER Embedded Studio使用技巧一文的延续。

1. 列选择

在编辑器中,按住Alt键并用鼠标框选,将执行列模式选择。

2. 快速找到文件

可以利用这个功能在工程文件堆中快速找到某个文件,比如文件名中包含了uart,点击“漏斗”图标,或使用快捷键Ctrl + ;,调出过滤栏,输入uart,即可列出所有相关文件。
Project File Filter

3. 扫描结果过滤

搜索关键字可能搜出大量匹配项,可以在搜索结果中进一步过滤。

Find Result Filter

4. 隐藏无效代码

工程中经常用#if 0宏开关让代码失效,可以设置无效代码的透明度,获得更好的视觉体验。
Tools --> Options --> Text Editor --> Inactive Code Opacity中设置5%,就可以得到下面效果

Inactive Code Color

5. 编辑工程文件

SES的工程文件(*.emProject)实际上是一个XML文件,某些场景下可以直接编辑它。
点击Project --> Open Solution in Editor,即可打开emProject文件。

Edit emproject file

6. 自定义宏标签

SES支持常规的TODO, FIXME宏标签,还支持自定义宏标签。在调试和读其他人代码的时候,尤其有用。
Tools --> Options --> Text Editor --> Attention Tag List中添加一个标签isyq,在代码注释中以isyq开头,即可高亮显示。

Customized Macro Tag

7. 跳转到编译错误

假如编译时报了多个编译错误,这些报错项可能夹在大量的编译信息中,手动查找的方式需要滚动半天,可以点击工具栏按钮或快捷键F4快速跳转到编译错误位置。

Build Warning Jumper

8. 串口终端

SES内置了一个简易的串口打印窗口,在调试时候不用再开第三方串口工具。
使用时候点击Tools --> Terminal Emulator

Intern UART Terminal

9. 预编译代码

代码中有的宏代码经过层层嵌套和拼接操作,无法直观的获知宏背后的原型函数和参数。

SES可以输出预编译后的文件,在当前源文件中,右键 --> Tools --> Show Preprocessor Output,即可打开一个名为xxx_PP.c的文件,该文件即源文件被预处理后的文件。
在追踪代码时候很有用。

Show Preprocessor Output

10. 工具栏大图标

现在显示器分辨率越来越高,小图标看着吃力。SES的工具栏图标可以设置为大图标,护眼。
Tools --> Options --> Environment --> Show Large Icon In Toolbars设置为Yes。

Toolbar Big Icon

(未完待续)

调试时遇到一段代码,精简后如下:

double val = 1 / (0 * 1.0);
uint32_t result = (uint32_t) val;

在Keil环境下(armcc v5.06)下,变量val = 0,result = 0,在Gcc环境下(arm-none-eabi-gcc v6.3.1)下,val = Inf(一个很大的数),result = 0xFFFFFFFF。

除法运算,除数不能为0。如果除数为0,该行为未定义(Undefined):

C99 6.5.5p5 – The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined. [link]

实践中,如果被除数是0,编译器会给出警告(Warning),但是上面代码里( 0 * 1.0 )的操作骗过了编译器的检查。

于是,Keil和Gcc两个不同平台的编译器给出了不同的结果。

猜测虽然C语言的规范没有定义,但具体到编译器身上,还是要给出一个数值结果——Keil给0,Gcc给Inf。

这种基础运算经常出现在库函数里不起眼的角落,并且会被重重嵌套。这个例子背后真实的代码是Thingy52里面sx1509的驱动代码[link]:

uint32_t fade_in_time_low_mult_reg = 
(uint32_t) round(
        (real_val->fade_in_time_ms /
        (REG_RISEFALL_TIME_LOW_MULTIPLIER *
        (reg_val->on_intensity - (4 * reg_val->off_intensity)) *
        (255 / m_clkx_tics_pr_sec))) / 1000);

这一行代码中涉及到了多种数据类型:uint8_t,整形宏,float,double, uint32_t,此外还有常量。不同类型数据混合运算,会发生隐式类型转换,代码中也同时使用了显式类型转换。这些东西混在一起写成一行,很容易产生BUG。

(完)