Expert C Programming 阅读笔记(~CH1)
P4: 好梗!
There is one other convention—sometimes we repeat a key point to emphasize it. In addition, we sometimes repeat a key point to emphasize it.
 
P5:UCB的UNIX文档里,tunefs命令的说明有一个叫Bugs的模块,最后一句吐槽道:
You can tune a file system, but you can't tune a fish.
    (tunefs = tune a fish = tuna fish,来自于REO Speedwagon的专辑You Can Tune a Piano, but You Can't Tuna Fish的冷笑话,在这里相当于:朽木不可雕也……)
有人加了一句comment威胁不许改掉这句吐槽不然就会受到诅咒:
Take this out and a UNIX Demon will dog your steps from now until the time_t's wrap around.
后来Sun在SVr4 UNIX的manpage里不仅把Bugs模块改称为Notes(你以为这样群众就不把它当槽点了嘛?),还斗胆删掉了这句吐槽,接下来发生的事大家都知道了LOL (Line Printer Daemon躺枪)
下面的练习围绕这句诅咒里的"until the time_t's wrap around"展开:什么时候time_t会wrap around呢?(相当于问从1970年1月1日零点经过time_t能正确表示的最大数的秒数之后是啥时间,比较常见的是long int,大约是2^31-1,也就是到2038年)
参考阅读:http://en.wikipedia.org/wiki/Year_2038_problem
查阅time.h,看到了句
typedef long time_t;
参考自己以前做过的探究
      http://www.cnblogs.com/joyeecheung/archive/2012/10/12/2720707.html
为了方便表示,利用二进制转十六进制4位合并一位的原理,我的电脑的time_t可以表示的最大正整数是
    ((2^32))/2-1 = 01111111111111111111111111111111 = 0x7FFFFFFF
剩下来的部分和书上的代码差不多啦:D
Notes:
  ctime()接受一个time_t的指针,返回这个time_t对应的以地时区为准的可读字符串;
  gmtime()接受一个time_t的指针,将它转化为以UTC为准的struct tm,返回这个struct tm的指针;
  asctime()接受struct tm的指针,返回一个ctime()返回的那种字符串。
  也就是说,要将一个time_t的秒数转化成一个容易看懂的字符串,如果转成本地时间只要用ctime(...),如果转成UTC则需要asctime(gmtime(...))
  当然,C的库函数还没有碉堡到能依据夏令时调整(何况用夏令时的时段也是不固定的),所以那些有夏令时的国家就……呵呵呵呵呵~~
programming challenge第二个问题的答案
#include <stdio.h>
#include <time.h> int main(void)
{
time_t now;
time(&now); time_t biggest = 0x7FFFFFFF; time_t gap;
gap = difftime(biggest, now); struct tm *timeptr = gmtime(&gap);
printf("%d years, %d months, %d days, %d hours, %d minutes and %d seconds\n",
timeptr->tm_year - , timeptr->tm_mon, timeptr->tm_mday,
timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
printf("before time_t's wrapped around\n");
return ;
}
结果是还有24年多,期待2038年XD
P8:
UNIX比C语言诞生得更早,最初是用PDP-7的汇编写的,所以不存在先有鸡还是先有蛋的问题。
UNIX和C语言标准库的时间从1970年算起是因为UNIX在1970年诞生。
作为一个比起看书更喜欢翘脚看纪录片的懒人看到这里立刻想找UNIX的纪录片来看……似乎没有电视台制作的,AT&T的官方youtube上有一个纪录片,因为语速慢+是美音,用youtube自带的听译字幕效果很不错
http://www.youtube.com/watch?v=tc4ROCJYbm0
某个程序猿在被PL/I虐过后怒写打油诗一首:
    IBM had a PL/I / Its syntax worse than JOSS / And everywhere this language went / It was a total loss.
介绍C语言前世时作者的措辞太碉堡了:
    ...After a brief and unsuccessful flirtation with Fortran, Thompson created the language B...
P9:
作者抱着务实求真的八卦态度,深刻批评了那些仅凭一条语句的编译效率就臆测C的++与--是为PDP-11而设计的八卦群众。
P10:
PDP-7的数据都以同样的大小存储,所以B语言没有数据类型,大家都是一个word。而PDP-11可以用不同大小的内存存储数据,为了帮助写编译器的人区分整数浮点数等等,C语言才加入了数据类型,这个事后加进去的类型系统没有经过认真的思量,所以它也它支持不同数据类型也能直接赋值这种充满陷阱的操作,不像pascal,python之类的语言那样对数据类型的约束那么强,结果就是:
To this day, many C programmers believe that "strong typing" just means pounding extra hard on the keyboard.
(其实我第一次看到strong typing这个词也是这么以为的,你是在逗我呢吧~ =____=|||)
C语言留下来的大量特性(也影响了很多其他的语言)都是“以编译器作者为本”才创造出来的:
    - 数列从0数起这个大坑是因为编译器作者们喜欢用offset来定位,这样寻址好算
    - 数据类型都是看着能直接对应硬件底层才加进来的,所以没有复数,有浮点数也是因为有了PDP-11的新功能
    - 对普通程序员看上去很多余的auto是因为编译器作者们弄symbol table的时候有用才存在的
    - 数组约等于指针方便了编译器作者,给普通程序员挖了个坑……
    - 早期的C语言里float和double没有区别,写了float也照样双精度,因为PDP-11转换精度很方便,加上某些PDP-11的浮点数硬件是切换模式的,要么就全部单精度要么就全部双精度,当时的UNIX又不怎么用得着float所以干脆都扩展成双精度的算了,省得切换来切换去……(真是懒啊……)
    - 不能嵌套函数:为什么?因为这样编译器好写(-__-||)
    - register把分配寄存器给常用变量的活丢给程序员干了(不过好在现在的编译器越来越极品已经可以自动把常用变量放进寄存器,不需要程序员特意注明了……)
P11:
为什么在其他语言里runtime support会默默调用,但是C语言一定要自己手动管理内存,检查数组越界,干各种各样的琐事捏?答案很简单——因为琐事都丢给程序员,编译器作者就不用操心了!-____-|||
出于一样的原因,C语言也不自带I/O,要用库函数(还记得大一C语言考试第一题就是问#include<stdio.h>是否必须,哇哈哈)。最早由Mike Lesk写了个臃肿的I/O,性能不太好,后面经过多次优化才变成现在的样子。讽刺的是Mike Lesk 在自己的书里反而写过
designing the system so that the manual will be as short as possible minimizes learning effort
作者表示看到这句话万千问候涌上心头,of which "Bwaa ha ha!" is probably the one that minimizes learning effort XD
讲C preprocesser的时候提到了String replacement, of the form "change all foo to baz",觉得应该有什么梗,就在维基查了一下foo和baz
http://en.wikipedia.org/wiki/Foobar
虽然经常见到foo不过挺少见到其他的。原来播放器的foobar名字是这么来的(也就是……乱起的忘改了……)
P12
如何把C语言从表面上改造成另一种语言……IOCCC就是这么来的:D
P15
为什么缩写是b+=3而不是b=+3?本来B语言的词法分析器是用=op比较方便的,但是容易搞混,比如b=-3和b= -3,多一个空格照样编译通过,但是差了十万八千里。改过语法之后某些formatter见到了=op就改成op=拿去编译,结果像a=!b就被改成了意思差十万八千里的a!=b……
教训就是,一个formatter应该乖乖修改whitespace,别没事干去乱动代码……
为了避免这个bug,一个解决办法是在运算符后面加个空格,可能这也是现在常见的编程风格要求双目运算符两边加空格的由来之一……(不过加上空格本身确实能提高可读性)
P16
为了处理8086不规则的芯片架构,微软搞了一个自己的编译器,加入了far和near之类的关键字。在ANSI C制定的时候IBM PC非常流行,所以小组成员对要不要加这些东西争论了很久,最后他们决定it was undesirable to mutate the language to cope with the limitations of one specific architecture.
P17
——到底是ANSI C还是ISO C?
  ANSI弄好标准后,被ISO修改并采用了,然后ANSI又用ISO修改后的版本代替了自己最初的标准,所以现在的标准是ISO确定的,应该叫它ISO C,虽然大家还是叫ANSI C的多,因为早在ISO WG14成立前ANSI C都就已经叫开了,群众都已经习惯了。不过作者表示叫它ANSI C也是appropriate的,因为最后敲定标准的时候ISO和ANSI都有出力。
标准实体书这个玩意果然无论在什么行业什么国家都是很贵的 = =b 不过作者写书的年代网络盗版还没这么流行,现在ISO/IEC 9899-1990的电子版已经很好找了,尤其是在不知版权为何物的兔子or毛熊国
作者表示有八卦传闻说要给C加上复数类型,不过今天看来是没实现……
P19
按照标准,只要不违反明文规定的constraint,编译器都可以不警告你,即使只是undefined,这时编译器想干啥都可以,也就是所谓的implementation-defined的行为
Useful rule from Brian Scearce — if you hear a programmer say "shall" he or she is quoting from a standard. :D
P21
其他语言都在对语言特性的最大值作规定,但ANSI C却净是对最小值的规定,奇葩的是,这些规定又没有被定性为constraint,所以就算编译器达不到要求,照样可以不给警告……
A really good implementation won't have any preset limits, just those imposed by external factors.
P24
- K&R C中并没有prototype。ANSI C从C++借鉴了这个特性。
- 对于一个prototype来说,parameter的信息比它的名字和return value type更重要(这也是为什么用parameter和名字组成signature而return value type在其中不起作用)。
- 有了prototype,编译器可以在编译时就检查参数传递是否正确,而没有prototype就只能等到连接的时候再检查甚至直接被忽略了。同时function header的形式也发生了改变。
- 最好不要删除prototype中parameter的名字,以便为使用者提供更多的信息
- 最好给所有新东西都加上个prototype以防万一
P26
language lawyer :
    a person who will show you the five sentences scattered through a 200-plus-page man ual that together imply the answer to your question 'if only you had thought to look there.'
            —— The New Hacker's Dictionary
P27
从这里开始各种绕晕…………=_____=|||||
const char * = char *的赋值成立的原因:
    左边指向的是const char,即被指的类型是qualified by const;
    右边指向的是char,即被指的类型是unqualified;
    这时候符合ANSI C 6.3.16.1描述的情形:
        type pointed to by the left has all the qualifiers of the type pointed to by the right
    注意qualified by const = qualified by const + unqualified,1 = 1 + 0, 有包括没有
const char ** = char **的赋值不成立的原因:
    首先根据ANSI C 6.1.2.5,const char *本身是unqualified的,即使它指向的是qualified by const
    左边指向的是const char *,故被指的类型是unqualified
    右边指向的是char *,同样也是unqualified
    两边的指针均指向unqualified,而两个unqualified的被指内容又不是一个类型,即具有不同的qualifier,所以不符合ANSI C 6.3.16.1 ,不能赋值。
根本原因是6.3.16.1 对指针之间赋值的合法性只看下一级,再往下的不管关系多亲都没用,也就是Compatibility of pointer types is not transitive。
当然这个混乱的约定并不是所有编译器都在遵守,有的执行得比较灵活。
嗯,没事干研究这种东西的人确实担得起language lawyer的美名……
P27
const并不能把variable变成constant,它还是一个variable,只是限制你不能用它通过赋值来修改变它的值,variable在内存里该放哪它还是放哪。给人缠上防护绷带,不代表他们就变成了木乃伊。
最常见的用法:const xx *实现安全高效的call-by-reference
一个const int *可以指向一个普通的int,被指的变量类型不会变(不会进化成const int),指针本身的意思也不会变——你不能通过这个指针去修改它指的东西。
当然,你不能用这个指针修改它指的东西,不代表你不可以用其他方式(比如用另一个普通指针)去修改它指的东西。假如有个神经病不许你用vim改文件,只许你用vim看文件,你一样可以用emacs改了它,然后用vim阅读修改后的文件。
const只是一个符号,它不会改变什么实质性的东西,只是在一个特定范围加个约束而已。所以不要真心去指望一个const int *指针dereference后得到的还是原来的内容,靠不住哇。
P28
In retrospect, the const keyword would have been better named readonly.
ANSI委员会再次被嘲笑……
ANSI C的promotion规则简而言之就是:
    Operands with different types get converted when you do arithmetic. Everything is converted to the type of the floatiest, longest operand, signed if possible without losing bits.
在不同整型的正负数同时出现时,ANSI对较小的整型的处理比K&R更可靠。两者都有一个易见的BUG:只要有一个unsigned int,如果旁边还跟着一个负数,那就要遭殃。解决方案是把那个unsigned int转化成int再来进行运算。而最好的方案是尽量别用任何unsigned类型,世界就清净了……
一般可以安全用unsigned的场合是用二进制的时候,不然即使你要表达的数全是正数,只要signed的容量够,也没必要硬用unsigned。
P31
算数组元素数量:
  用sizeof(array) / sizeof(array[0])
  不用 sizeof(array) / sizeof(int)
这样万一改了array的类型,可以少一份工
P32
有位gcc的开发者曾经强烈抵制过#pragma,并且将ANSI所谓的implementation-defined发挥到了极致:在gcc 1.34的手册中写明,如果喂进去一段有#pragma的代码,它不但不会编译,反而会试图启动游戏rogue,如果不行就启动游戏hack,再不行就打开emacs放汉诺塔,全都不行了也要报个fatal error,这是多大仇……
作者还无比充满八卦精神地附上了相应的preprocessor代码……“乃要implementation-defined, 我就define给你看”,这开头的注释是有多幼稚啊摔!
/*
* the behavior of the #pragma directive is implementation
defined.
* this implementation defines it as follows.
*/
身为八卦表率的作者又不忘敬业地指出,这版的手册写错了,应该是先试打开hack再试打开rougue……=__=b
Expert C Programming 阅读笔记(~CH1)的更多相关文章
- Expert C Programming 阅读笔记(CH2)
		
P33 Bugs are by far the largest and most successful class of entity, with nearly a million known ...
 - Mongodb Manual阅读笔记:CH3 数据模型(Data Models)
		
3数据模型(Data Models) Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mon ...
 - C语言学习书籍推荐《C专家编程Expert C Programming Deep C Secrets》下载
		
Peter Van Der Linden (作者) <C和C++经典著作 C专家编程Expert C Programming Deep C Secrets>展示了C程序员所使用的编码技巧, ...
 - 阅读笔记 1  火球 UML大战需求分析
		
伴随着七天国庆的结束,紧张的学习生活也开始了,首先声明,阅读笔记随着我不断地阅读进度会慢慢更新,而不是一次性的写完,所以会重复的编辑.对于我选的这本 <火球 UML大战需求分析>,首先 ...
 - [阅读笔记]Software optimization resources
		
http://www.agner.org/optimize/#manuals 阅读笔记Optimizing software in C++ 7. The efficiency of differe ...
 - 《uml大战需求分析》阅读笔记05
		
<uml大战需求分析>阅读笔记05 这次我主要阅读了这本书的第九十章,通过看这章的知识了解了不少的知识开发某系统的重要前提是:这个系统有谁在用?这些人通过这个系统能做什么事? 一般搞清楚这 ...
 - <<UML大战需求分析>>阅读笔记(2)
		
<<UML大战需求分析>>阅读笔记(2)> 此次读了uml大战需求分析的第三四章,我发现这本书讲的特别的好,由于这学期正在学习设计模式这本书,这本书就讲究对uml图的利用 ...
 - uml大战需求分析阅读笔记01
		
<<UML大战需求分析>>阅读笔记(1) 刚读了uml大战需求分析的第一二章,读了这些内容之后,令我深有感触.以前学习uml这门课的时候,并没有好好学,那时我认为这门课并没有什 ...
 - Hadoop阅读笔记(七)——代理模式
		
关于Hadoop已经小记了六篇,<Hadoop实战>也已经翻完7章.仔细想想,这么好的一个框架,不能只是流于应用层面,跑跑数据排序.单表链接等,想得其精髓,还需深入内部. 按照<Ha ...
 
随机推荐
- 【codechef】Children Trips
			
Portal -->CC_Children Trips Solution (英文题解看得真爽qwq不过写的好详细啊ovo) 首先这题有一个很重要的条件就是边权是\(1\)或者\(2\),所以虽然 ...
 - win7系统用笔记本共享wifi热点 让手机免费上网
			
之前一直在用这个方法把自己的笔记本变成一个wifi热点,让手机也可以直接连wifi上网,节省网费和路由器购买费. 其实就是开启了windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP ...
 - 手脱Upack 2.x - 3.x
			
1.PEID查壳 Upack 2.x - 3.x Heuristic Mode -> Dwing 2.载入OD,一上来就是一个大跳转,先F8跟一会 >- E9 56D40300 jmp 跑 ...
 - RabbitMQ的基础介绍
			
转自:http://blog.csdn.net/whycold/article/details/41119807 一.引言 你是否遇到过两个(多个)系统间需要通过定时任务来同步某些数据?你是否在为异构 ...
 - Uniform Distribution均匀分布
			
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&am ...
 - SpringCloud学习(3)——Eureka服务注册中心及服务发现
			
Eureka概述: Eureka是Netflix的一个子模块, 也是核心模块之一.Eureka是一个基于REST的服务, 用于定位服务, 以实现云端中间层服务发现和故障转移.服务注册与发现对于微服务框 ...
 - 算法专题-STL篇
			
这篇文章着重记录c++中STL的用法.主要粗略的介绍其用法,以知识点的形式呈现其功能,不会深入源码分析其工作原理. 排序和检索. sort(a,a+n),对a[0]往后的n个元素(包括a[0])进行排 ...
 - 贪心法:K叉哈夫曼树
			
NOI2015荷马史诗 一部<荷马史诗>中有 n 种不同的单词,从 1 到 n 进行编号.其中第 i 种单词出现的总次数为 wi.Allison 想要用 k 进制串 si 来替换第 i 种 ...
 - HDU 6199 DP 滚动数组
			
强行卡内存 这题在CF上好像有道极相似的题 可以想到状态设计为dp[f][i][k]表示f在取完i-1时,此时可以取k个或k+1个的状态下的最大值.之前以为n是1e5,自己想不到怎么设计状态真的辣鸡, ...
 - codeblocks快捷键(转)
			
==日常编辑== • 按住Ctrl滚滚轮,代码的字体会随你心意变大变小.• 在编辑区按住右键可拖动代码,省去拉(尤其是横向)滚动条之麻烦:相关设置:Mouse Drag Scrolling.• Ctr ...