前阵子因为要折腾 VPS 的缘故把博客暂时放在了 @likounin 童鞋的服务器上,不想最近他的服务器出了点问题,于是只能赶紧把 VPS 重新折腾回原样,然后把博客搬回来。
慌忙折腾之中遇到个问题:在 SSH 里卡住了,没法 Ctrl-C
(因为这种按键会直接发给远端),该怎么正常退出?
想来也应该有个转义序列可以直接对 SSH 做操作……于是,那就是 ~
键。
SSH 到服务器后,确保之前按过一次回车,然后按 ~?
,就会列出一堆可用的转义序列,比如:
Supported escape sequences:
~. - terminate connection
~B - send a BREAK to the remote system
~C - open a command line
~R - Request rekey (SSH protocol 2 only)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
总之,要退出已经卡住的 SSH 程序,可以在按一次回车(见上面帮助信息的最后一行)之后,按下 ~.
。
话说回来,转义字符也只是默认是这个 ~
字符而已,如果不喜欢的话,ssh_config
文件中有一个选项叫 EscapeChar
可以修改转义字符。
以上。
于是又是一篇木有技术含量的笔记。
对于 Unicode 窗口,WM_IME_CHAR
和 WM_CHAR
没有区别,wParam
都是一个 WCHAR
,即输入的字符。
对于非 Unicode (DBCS) 窗口,WM_IME_CHAR
的 wParam
即由输入法生成的一个字符。这个字符既有可能是单字节字符也有可能是双字节字符。如果是单字节字符,那么和 WM_CHAR
没什么区别;如果是一个双字节字符,那么 wParam
高 8 位为 Leading byte,低 8 位为 Continuation Byte。
所有经由输入法产生的字符都会产生 WM_IME_CHAR
消息而不是 WM_CHAR
,但 DefWindowProc
会把 WM_IME_CHAR
转换为相应的一个或两个 WM_CHAR
消息。
例如:
- 不开输入法输入「9」 → 收到
WM_CHAR
(0x0039)
- 打开输入法输入「9」 → 收到
WM_IME_CHAR
(0x0039) → 收到 WM_CHAR
(0x0039)
- 打开输入法输入「笨」 → 收到
WM_IME_CHAR
(0xB1BF) → 收到 WM_CHAR
(0x00B1) → 收到 WM_CHAR
(0x00BF)
微软什么的最讨厌啦~写个 GUI 程序要么带个控制台窗口,要么就得用非主流的 WinMain
函数作入口。
用 gcc 的话,这其实不是个问题,带上一个 -mwindows
参数即可顺利解决掉控制台窗口并且抛弃 WinMain
。
而到了 Visual Studio,似乎很两难:
- Linker 参数中 SubSystem 选择 Windows 可以去除控制台窗口,但会要求用
WinMain
作入口。
- Linker 参数中 SubSystem 选择 Console 可以使用
main
作入口,但会自带控制台窗口。
于是困惑了。好在今天在 Irrlicht 的教程中见到了解法:
Linker 参数中的 SubSystem 继续选择 Windows,与此同时将 Entry Point 设置为 mainCRTStartup 即可兼得鱼和熊掌。
以命令行参数形式就是:/SUBSYSTEM:windows /ENTRY:mainCRTStartup
要点就是 ENTRY 参数有三种:mainCRTStartup、WinMainCRTStartup、和 _DllMainCRTStartup,分别对应调用 main
、WinMain
、和 DllMain
,默认是根据 /DLL 和 /SUBSYSTEM 参数自动选择的。
以上。
一说筛选数据首先映入脑海的是 grep,但 Windows 下就悲了个具了,从别程序复制(这时候觉得 GUI 不能管道真是太糟糕了)了一坨纯文本数据要筛选,为了这个还要临时保存个文件然后再开个 Cygwin 啊~MSYS 啊什么的真是太不适合我这种懒人了。于是还是要拜托好用的 Vim 来处理。
假设要在某坨数据中删除含有「kernel32」的行,可以执行:
:g/kernel32/d
其中中间的条件部分 kernel32
和一般的查找条件格式相同,最后部分的 d
则和一般的命令按键相同。如果要保留匹配的行则可以把开头的 g
替换为 g!
。
这样的写法实际是使用了 VIM 的「Multiple Repeats」功能,完整格式是这样的:
:[range]g[lobal]/{pattern}/[cmd]
详情请参考 :help :g
:)
最近不是特别忙,于是就抽空开始继续看 PIL 了。
变量声明与 C 语言的不同
Lua 中有一个常见的用法,不论变量、函数都可以用下面这种方法保存到局部变量中(同时加快访问速度):
local foo = foo
书里加了个括号来解释这种写法:
The local foo
becomes visible only after
its declaration.
这一点需要瞎扯的是 C 语言里相应的东西。
int foo = 12;
int bar = 6;
void foobar(void)
{
int foo = foo;
int bar[bar];
}
与 Lua 不同,在 C 语言中初始赋值是声明之后的事情。所以这里函数 foobar
中的 foo
会被初始化为自己(而不是全局的 foo
,所以值不确定),bar
却被合法地定义为一个含有 6 个元素的数组。
看似多余的限制
另一个有趣的现象是在 4.4 节中说到:
For syntactic reasons, a break
or return
can appear only as the last statement of a block; in other words, as the last statement in your chunk or just before an end
, an else
, or an until
.
乍一看觉得加上这个限制真是麻烦,但想想这不正是 break
/return
的正确用法么?因为其后的语句都永远不会被执行到,所以如果不是在块的最后写 break
/return
是毫无意义的(调试除外)。虽然看上去是挺多余的一段话,但也算是说出了事物的本源。
函数的本质
第六章 More About Functions 中说到我们平时在 Lua 中写的函数声明
function foo (x) return 2*x end
其实是一种语法糖,本质上我们可以把它写成如下代码:
foo = function (x) return 2*x end
于是也就可以说
- Lua 中的所有函数都是匿名函数,之前所谓「具名函数」只是保存了某个匿名函数的变量罢了。
- Lua 中的函数声明其实只是一个语句而已。
终于有用的知识
在第 47 页看到了一段令人泪流满面的代码和运行结果:
function derivative (f, delta)
delta = delta or 1e-4
return function (x)
return (f(x + delta) - f(x))/delta
end
end
c = derivative(math.sin)
print(math.cos(10), c(10))
--> -0.83907152907645 -0.83904432662041
最初我并不知道 derivative 是什么意思,但看了示例代码和运行结果,顿时恍然大悟:这货不就是导数吗?
高数里的东西竟然真的在现实生活中出现了!顿时觉得世界真美好 =ω=
- «
- 1
- ...
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- ...
- 18
- »