1. umask 豆瓣网友指出,微信读书有个好处,就是能看到别人的标注和笔记,别人也能看到自己的。kindle也能共享,但是远没有微信方便和活跃。我就偷偷看别人的笔记,比如大家读古龙时候的感叹。有时猜测,这位读者是个孩子,那位读者觉得自己不是孩子了。有时自己也感叹,哇,当年没有读懂,或者当年肯定读不懂。有时还参与两句。 也看娄嘉鹏老师的技术笔记,他的很多阅读不是为了学习,而是考虑在教学中如何清晰讲解,比如下面这条就挺有意思。 娄老师标注的是文字原文是这样的,"特别强调一下,网络上有很多关于计算umask遮罩后权限值的讲解,比较主流但是错误的讲解方式是使用“同位相减”的做法来计算遮罩后的值"。 "特别强调一下",WJY同学表达过,这是相当有脾气的说法。作者的意思是"就这你还不明白?我还得再说一遍。"对这句话,教师当慎言。 (1) 后面作者提到了错误的看法,还举了例子。用 权限666 减去 掩码011,同位相减得到权限值 655。这个结果是错的,正确的权限值是 666。 为啥正确呢,不知道。作者没有给出正确的算法。教学中教师通常容易犯的错误是只把正确的说了,但是(既不说原理,也)不说哪些是错的。比如深蹲时双脚就像旋入地面,原理是绷紧下肢提高对膝盖的控制,尤其是最低端,对应的错误是大腿 (内侧?) 放松。教练就说,旋进地面啊,拳要打进去,站直,你怎么连什么是站直也不会,不是超伸。好,终于说到了什么是不对的。 正确的权限值是 666,这可以通过实验验证,但是原理还是不清楚。 作者说,权限666 和 掩码011 间的运算,当作按位减是不对的,那么什么是对的呢?对这个算法的描述,作者用的动词是"遮罩掉"。遮罩就是掩码mask。但是,"遮罩掉"是个什么操作,难度不 (显然) 是按位减么?作者定义了个名词,但是没有解释。 上网搜索一下,比如[https://www.cnblogs.com/wish123/p/7073114.html]在《Linux中设置UMASK值》这篇博客用的动词是,从最大权限777中"去掉"umask值。 遮罩掉、去掉,有同学说,不是挺明白的么? (2) 什么是明白?就是能编程序实现。C语言里有定义遮罩掉、去掉这两个函数或操作符么。你是不是又想做按位减法了。 对了,娄老师标记这段话时,是怎么评论的呢?他说,"一般与掩码与,umask取反与"。我最初没看明白,但是娄老师这句话显然比作者更靠谱,至少 与、取反这样的术语,比"遮罩掉、去掉"更接近机器的语言。在靠谱这个意义上,不说遮罩掉、去掉这样的人话,更像是做人事。 我没问娄老师到底啥意思,又不急着知道,觉得自己想想挺好玩的。 事实上,我能体会到 遮罩掉、去掉 的含义,也就是说,我可以枚举/穷举出所有的结果,而且这本书里有例子可以验证。于是我打了个表格,以下第一列p代表 privilege权限,第二列是umask,第三列是求出的结果。 |P | umask | r | |0 | 0 | 0 | |0 | 1 | 0 | |1 | 0 | 1 | |1 | 1 | 0 | 看第2行即010,确实不是按位减。这一位,也就是作者举的 666 去掉 011 以后 得 666,而不是 655,6或5转换成二进制为110和101的最后一bit。 110 ? 001 ------- 110 有个这个表格,我们可以写一大堆if-else……了。 (3) 不优雅啊,我估计RH和GYB同学会这么说。 离散数学课和数字电路课上,我们学过把真值表转换成逻辑表达式。过程略过,结果是 r = p & !umask 这说我想起了娄老师说的话,"umask取反与",umask取反,然后与p。 2. 补码 什么时候用补码?负整数在计算机中用补码表示。 为什么需要补码?通过补码,CPU可以使用加法器做减法计算。 怎么算补码?反码加1。 为什么? 那些天同时在看这本书,[https://book.douban.com/subject/25882201/],From Mathematics to Generic Programming。看到补码运算的时候写了一段笔记,简单解释补码计算的原理。 (1)补码 补码是什么? 补码 = 模 - 数 ..................公式1 模是什么?模是进制的大小。钟表12进制,模就是12。人类用10进制,模是10。 模12的例子: (-3) = 12 - 3 = 9 ;9点是差3个小时12点 (-2) = 12 - 2 = 10 ;10点是差2个小时12点 模10的例子: -2 = 10 - 2 = 8 模8的例子: -2 = 8 - 2 = 6 对上述例子中的最后一个,模8中的-2,我们验证一下。 二进制下2取反+1, (010)-> 取反 -> (101) -> +1 -> (110) -2 ->->->->->->->->->->->->-> 6 (2)取反 取反操作 <=> (模-1)-数 ............公式2 这是因为 数+反 = 模-1 看两个例子 001 + 110 ------ 111 010 + 101 ------ 111 (3)推导 取反 <=> (模-1) - 数 ..........根据公式2 取反 + 1 <=> (模-1) - 数 + 1 ..........左右都加1 取反 + 1 <=> 模 - 数 .......... -1+1 => 0 取反 + 1 <=> 补码 .......... 公式1 所以"取反+1"就是补码。
(4)原理 基于的原理是 : 模 就是 0。 12点就是0点,毕十10就是零蛋。限制位数,0x100,就是 0x00。 更深层的原理是因为 : 求余,求模。 这就是为什么求余运算的名字是求模的原因吧。 (5)编码举例 除去符号位 (假设模8) ,以下每行的两个数字编码相同。 | +0 | -0 | | 1 | -7 | | 2 | -6 | | 3 | -5 | | 4 | -4 | | 5 | -3 | | 6 | -2 | | 7 | -1 | 每行的两个数字,它们绝对值的和是8,即模。 举例,-7的补码是 原码 111, 按位取反得到 000, 加1得到 001. 刚好与同一行的 1 的原码 001 相同。 我们还能注意,负数里面还有个 -0。 3. ASCII 这段非常短,就是想回答下不少同学可能有过的疑惑,ASCII里为什么 A是65,a是97,这么有零有整的。不怎么好记啊。 因为,如果你不看两列的ASCII码表,而是找一下16行16列的ASCII码表就会发现,或者按十六进制就会发现,就像1024是整数,'A'和'a'都是整数。 A 是 0x41,即4*16+1 = 65; a 是 0x61,即6*16+1 = 97。 还有'0',是0x30,即 48。 为什么ASCII要在大写、小写、数字之间加些乱七八糟的字符,逗号、冒号、方括号,还不把这些符号连续地放在一起。正是为了填充,让A、a、0在整数开头吧。