“If I had eight hours to chop down a tree, I'd spend six hours sharpening my axe.” – Abraham Lincoln
「如果我有8 小时可以砍1 棵树,我会花6 小时把斧头磨利。」(类似汉语「工欲善其事,必先利其器」的精神) – 亚伯拉罕.林肯
语言规格:
C89/ C90 -> C99 -> C11 -> C17/ C18 -> C2x
C 语言老爸的评论
「C 很别扭又缺陷重重,却异常成功。固然有历史的巧合推波助澜,可也的确是因为它能满足于系统软件实践的程序语言期待:既有相当的效率来取代组合语言,又可充分达到抽象且流畅,能用于描述在多样环境的演算法。」
C is quirky, flawed, and an enormous success. Although accidents of history surely helped, it evidently satisfied a need for a system implementation language efficient enough to displace assembly language, yet sufficiently abstract and fluent to describe algorithms and interactions in a wide variety of environments. —— Dennis M. Ritchie
![你所不知道的C语言:开发工具和规格标准](http://p2.ttnews.xyz/loading.gif)
为什么我不探讨C++
- 在台湾发文好像爱用「为什么我不」开头,后面可接「念研究所」、「待在大公司」等描述
- C++ 自称为面向对象的程序语言,却不愿意对对象在执行时期的表现负责任
若说C 语言给了你足够的绳子吊死自己,那么C++ 给的绳子除了够你上吊之外,还够绑住你身边的朋友
相较之下,Java 让你在吊死自己之际仍有亲友监视着,虽然死不了,但事后会更想死
In Ruby, everything is an object.
In Clojure, everything is a list.
In Javascript, everything is a terrible mistake.
in C, everything is a representation (unsigned char [sizeof(TYPE)]).
- Linus Torvalds 在2010年的解释(下划线是个链接)
https://www.realworldtech.com/forum/?threadid=104196&curpostid=104208
- C++ 实际上已经是截然不同的程序语言
C++老爸Bjarne Stroustrup的文章: “ Learning Standard C++ as a New Language ”
文章链接地址:http://www.stroustrup.com/new_learning.pdf
- 最重要的是,C++ 改版飞快,C++ 17 即将推出,但我还没看懂C++ 98
![你所不知道的C语言:开发工具和规格标准](http://p2.ttnews.xyz/loading.gif)
延伸阅读
- 没有C语言之父,就没有Steve Jobs ( 原文 )
https://buzzorange.com/techorange/2015/10/19/without-dennis-ritchie-there-would-be-no-steve-jobs/
这个链接已无法打开
- 第一个C 语言编译器是怎样编写的?
https://www.csdn.net/article/2015-11-27/2826350
读规格书可大幅省去臆测
在ISO/IEC 9899 (aka C99 Standard)中5.1.2.2.1内有提到C Standard要求main函数必须这样写
<code>int main(void) { /* ... */};/<code>
或者:
<code>int main(int argc, char *argv[]) { /* ... */ };/<code>
C++之父Bjarne Stroustrup的个人网页内有个FAQ里面有个问题叫Can I write “void main()”?
然而在C++与C的标准中从来没出现过这样的写法,也就是说,void main()这个写法从来没正确过
延伸阅读
- C 语言中int main() 和void main() 有何区别?(https://www.zhihu.com/question/60047465)
- C++ 的void main() / int main() … 不要再用void main() 了! | Peter Dave Hello's Blog(https://www.peterdavehello.org/2014/10/void-main-int-main-in-c-and-cpp/)
- void main(void) - the Wrong Thing(https://www.ty-penguin.org.uk/~auj/voidmain/)
ISO/IEC 9899 (简称“C99”)
- 从一则笑话谈起“Programming in C: if it doesn't work, just add a star. Or multiple stars. Or ampersands.”
- 规格书 (PDF)搜寻“ object ”,共出现735处(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)
搜寻“ pointer ”,共出现637处。有趣的是,许多教材往往不谈object,而是急着谈论pointer,殊不知,这两者其实就是一体两面
object != object-oriented,前者的重点在于「数据表达法」,后者的重点在于“everything is object”
C11 ( ISO/IEC 9899:201x ) (http://port70.net/~nsz/c/c11/n1570.html)
- 从第一手资料学习:大文豪写作都不免要查字典,庸俗的软件开发者如我们,难道不需要翻阅语言规格书吗?难道不需要搞懂术语定义和规范吗?
- & 不要都念成and,涉及指针操作的时候,要读为“address of”
C99 标准[6.5.3.2] Address and indirection operators 提到'&' address-of operator
- C99 [3.14] object
region of data storage in the execution environment, the contents of which can represent values
在C 语言的物件就指在执行时期,数据储存的区域,可以明确表示数值的内容
很多人误认在C 语言程序中,(int) 7 和(float) 7.0 是等价的,其实以数据表示的角度来看,这两者截然不同,前者对应到二进位的“111”,而后者以IEEE 754 表示则大异于“111”
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.
关键描述!规范void *和char *彼此可互换的表示法
<code>void *memcpy(void *dest, const void *src, size_t n);/<code>
- C99 规格书的解释就比很多书本清楚,何必舍近求远呢?
EXAMPLE 1 The type designated as float *has type "“pointer to float'”. Its type category is pointer, not a floating type. The const-qualified version of this type is designated as float * constwhereas the type designated as " const float *is not a qualified type — its type is "“pointer to const qualified float'” and is a pointer to a qualified type.
EXAMPLE 2 The type designated as " struct tag (*[5])(float)has type “array of pointer to function returning struct tag'”. The array has length five and the function has a single parameter of type float. Its type category is array.
- Understand more about C提及若干起因于不同的C语言标准,而使得程序码行为不同的案例(https://www.slideshare.net/YiHsiuHsu/understand-more-about-c)
规格不能只看新的,过往也要熟悉
- 空中巴士330 客机的娱乐系统里头执行14 年前的Red Hat Linux,总有人要为「古董」负责
- 而且空中巴士380客机也是如此
为何C 语言标准函式库里头的函式名称如此简短?像是
- strcpy
- strlen
最初链接器有6 到8 个字符的输入限制!
Translation limits
6 significant initial characters in an external identifier
- 延伸阅读
Why did ANSI only specify six characters for the minimum number of significant characters in an external identifier?(https://stackoverflow.com/questions/38035628/c-why-did-ansi-only-specify-six-characters-for-the-minimum-number-of-significa/38042724#38042724)
Identifier(https://en.cppreference.com/w/c/language/identifier)
The Design and Evolution of C++一书对应的解说:(http://www.stroustrup.com/dne.html)
英文很重要
安装cdecl程式,可以帮你产生C程序的声明。
<code>$ sudo apt-get install cdecl/<code>
使用案例
<code>$ cdecl
cdecl> declare a as array of pointer to function returning pointer to function returning pointer to char/<code>
会得到以下输出:
<code>char *(*(*a[])())()
/<code>
把前述C99 规格的描述输入,可得:
<code>cdecl> declare array of pointer to function returning struct tag
/<code>
<code>struct tag (*var[])()/<code>
如果你没办法用英文来解释C 程序的声明,通常表示你不理解!
cdecl 可以解释C 程序声明的意义,比方说:
<code>cdecl> explain char *(*fptab[])(int)
declare fptab as array of pointer to function (int) returning pointer to char/<code>
只用printf 观察数据,有问题吗?
- 只用printf()观察的话,永远只看到你设定的框架(format string)以内的数据,但很容易就忽略数据是否合法、范围是否正确,以及是否看对地方
- printf()大概是最早被记下来的函数,也困扰很多人,有意思的是,1960年代初期MIT开发的CTSS作业系统中,终端机命令就包含了printf,后者一路从Multics和Unix继承至今
- 在CTSS原始程序源码com3中可见到这行STMTDC PRINTF,11,T,T25,前一行注解写“The following tables are the dictionaries of statement types”
不要急着打印数据,善用GDB
- 「学会了GDB,我有种山顶洞人学会用火的感动」 – 张至
- GDB Rocks!
- Introduction to gdb
- Debugging with GDB
- 除错程序: gdb
- 透过GDB 学习C 语言
说明:关于GDB这些地址的正常情况下,链接都已经无法访问,所有这里的链接地址我暂时不贴出来
除了Vim,我推荐Visual Studio Code
- Microsoft 开源Visual Studio Code (VS Code)
閱讀更多 kGavin 的文章