正确地黑C
转载:http://tieba.baidu.com/p/3190068223?pn=1
本版暂时当作提纲,不做详细展开讨论,以后可能更新。
注意:本文主旨不是政治正确。
1.设计
C的设计相对于同期来说是局促的。C语言具有明显的历史局限性是不争的事实。
类型系统是一个显著的例子。理论上,typed lambda calculus在当时(70年代)即便没有流行也已经有了数十年的发展,但是C的设计并没有有效利用当时的理论成果,还在前人的经验上开洞(比如奇葩的函数指针转换)。
类似地,数组类型也不是第一类实体,也会有类型上的修正。
这些无聊的设计除了让抽象变复杂,限制用户的自由外,唯一的好处也许就是顺应之前的具有局限性的语言实现的习惯了。不过,今非昔比,这样的设计并没有简化现在的语言实现——不管是C还是其它语言。
这种仓促的设计影响深远。C++至今仍然把一些肇始于C的奇葩转换保留在“标准转换”中,以至于重载的规则加倍复杂——考虑到兼容问题以及维护规则本身的困难,这些无谓的复杂性今后可能永远也无法移除。
左值(lvalue)是一个不幸的设计。一开始作为文法性质,并没有考虑到潜在的复杂,以至于后来引入const后,功能和区分左值在相当大范围内重复了(若完全一致反倒还好点)。这点另外有说过,按下不表。而这里重要的是,也无法指望丢弃冗余性(C++甚至变本加厉)。
当然,考虑历史的主干,C来自于B,来自于BCPL,来自于CPL,来自于ALGOL 60,来自于ALGOL 58,来自于FORTRAN。这些语言都没有这方面的合理经验积累。所以C的设计的局限,并不难想象。
也有一些其它的不足之处——丢弃有用的特性导致的倒退。不过,有些被纠正过来了,例如BCPL后扔掉的单行注释(//),被某些C方言、C++和C99以及其它一些C-like派生重新吸收。
还有一些奇葩的莫名其妙的地方。B里面叫vector的东西说的好好的,怎么到C里面就变成array了呢?只是因为加了个残疾的“数组类型”?(B是没好意思说成有类型的……)为什么array而不是vector就非得能对元素“O(1)访问”——这种偏见是谁发明的?(另一个不良后果是A.Stepanov搞STL的时候没词了就顺手捡了个……)
2.标准化的有效性
不能否认,在被规范化的语言(而不是实现)针对平台的可移植性来讲,C差不多应该是现在的语言中最强的了。ISO C++在某些少数极端情况下的可移植性的确不如ISO C(见WG21/N4049)。而其它语言,假定1字节不等于8比特的大小就足够打退堂鼓,若不够可以再加上允许原码/反码作为有符号数表示——这两者是ISO C和ISO C++都明确支持而其它大部分语言规范都与之矛盾的东西。
标准化的一个重要作用是取得共识,避免一些重复工作,提升可移植性,减轻用户(包括实现者)的负担。若标准被架空而没有被实际使用,标准本身就失去了绝大部分意义。
这里的一个反面素材是C#,.NET的实现都出到5.0了,ECMA-334到现在还是当年2的版本……(还有C#里把finalizer叫成destructor的奇葩导致混乱的说法在ECMA里被纠正了,MSDN上仍然将错就错。)
啥,ECMA是区域性组织,不够权威?——人家现在叫ECMA International好不好。不过不够权威好像是能坐实点,C++/CLI在ISO标准化被英国的意见驳回,ECMA就通过成ECMA-372了……
那么这里就拿C++比较好了。同样是ISO/IEC JTC1/SC22下的工作组,两者的产出看似类似,效果大相径庭。
而敢无视WG21的实现——据我所知,一个都没有。即便GNU早年隐晦地表达过和标准划清界限,现在来看在C++前端是口嫌体正直了。反观GNU C,这个效应就弱得多。
简而言之,ISO C虽然整体上是有效的,但是对于语言实现者来说,效力略为不足。
概括起来,这有两方面原因。
其一是WG14本身的活动没有WG21强调“open”。WG21的文档早就被公开多年,而WG14的没记错的话到2012年才被公开。
可能是由于C++本身的复杂性以及历史教训(轻率引入export和dynamic exception specification)需要避免消极的design by committee的影响,参与C++工作讨论的非委员会用户活动非常显著,Google Groups里讨论标准提议的论坛已经开设了好几年。isocpp.org也是一例。WG21甚至在github上拥有公开仓库允许用户pull request修改标准草案的内容。
反观C方面呢?一个对应的东西都没有。
作为工作产出来看,WG14公开的paper也要比WG21少得多(得多……)
C++比起C真有复杂到这种程度么?还是说C的“社区”(暂且这么说)在传统上就“不够进取”?或者根本不愿意达成共识呢?
第二点恐怕未必。POSIX就比较活跃了。
可笑的是,维护POSIX的Austin Group和WG14之间也能出现琐碎的意见分歧。参见WG14/N1174。
原因是其二——还是C的设计。
C欠缺了太多东西。
上面的隐晦分歧就是指,是不是在标准化的接口中,允许函数返回动态分配的对象然后让用户自行释放?ISO C的意见是“不”——于是asprintf乃至strdup都不可能出现在ISO C标准库,但这个原则之前看来从来没有被正式提起过。而POSIX方面以及其它传统C用户大概不会这么认为(特别是GNU)。
其它主流语言里还有这种奇葩问题么?
而ISO C新引入的东西,很多也不是自身的设计。
ISO C11引入的sequenced before的wording,是WG21/N2239提出来的。注意,是C++的paper,C后来照搬过去了。
(嘛,C++比较激进删除了之前ISO C引进的sequence point,不过这里有个bug,漏了sequenced after这个定义,我邮件过去了,处理情况见github.com/cplusplus/draft/issues/61。)
C11同时照搬过去的还有多线程和atomic的基本概念。由于语言特性上的先天不足,C没法做到C++的优雅(虽然这词普遍恶心,但用在这里的确不错)。(看看那个奇葩的_Atomic……)
C11还不得不引入了某种意义上的“临时对象”,这种手段又是埋坑。
C11绝无仅有的东西呢?哦,比如generic-selection?我问一下,这里谁对_Generic有印象的?知道它是怎么回事的?能说清解决了什么问题,并且是怎么起作用的?有多少人在实际代码中用过?在其它语言中类似的东西是什么?
ISO C比ISO C++多出来的,特别是近来新添加的,差不多尽是广大C用户都难以认同的琐碎玩意儿……
WG14,请不要玩脱。
3.用户素质
本来我在这里不想攻击任何人。但是C的用户在辩护语言和实现表达自己的观点时,表现出来的槽点明显比其它语言的用户多得多,并且不少自以为得计,优越感爆棚。忍无可忍。
在这里起到负面影响的用户都可以概括成不同程度的“不懂装懂”“在不熟悉的领域里瞎BB”“误导”,不过可以分成那么几类(也有不少复合的):
a)原教旨主义
认为C是程序设计语言发展历史上的“正统”——却连老祖宗ALGOL的地位和影响都不知道,甚至和亲爹B语言之间的差别都一问三不知。
b)盲信
不管可以引证的依据和理性思辨而盲目认同一些经不起推敲的观点(比如C比起其它高级语言总是“性能高”“开发效率低”)。
c)无知
缺少其它语言的使用经验却臆测行为和实现。甚至对C自身的基本概念(比如“对象”“左值”“未定义行为”)都说不清楚。
d)不独立思考
缺乏怀疑精神,对符合固有印象的说法来者不拒,却不考虑理由。“我听说”……“人家×××就是用C写的!”
e)缺少专业基础
没有PLT常识,对其它语言品头论足,对其中和C设计不同之处——而不是不足之处做出非理性的批评。
从经验上来看,这些用户中最核心的部分同时是UNIX的脑残粉——包括一些只用过Linux然后把自己包装成UNIX粉的。
这些用户,绝大多数都说不清楚C(也许还有UNIX)历史和发展方向之类的详细问题,要提一些现有实现的缺陷和可改进之处都支支吾吾,甚至说不清楚为什么好用,满足了什么需求(某些果粉都比他们更强一点)。
脑残粉本身不足一提,不过当一些“知名人物”也具有这些特质之后,他们就好像找到了什么被撑腰的了——却不知道很多“大师”在评论这里的问题上很多也是半外行,跟普通用户无异。
4.专治各种不服:有谁自认为对C本身了解更深刻而全面反对以上观点的(特别是挂名在WG14内的——有么?),欢迎对号入座战个痛。
EOF
正确地黑C的更多相关文章
- [工作积累] Google/Amazon平台的各种坑
所谓坑, 就是文档中没有标明的特别需要处理的细节, 工作中会被无故的卡住各种令人恼火的问题. 包括系统级的bug和没有文档化的限制. 继Android的各种坑后, 现在做Amazon平台, 遇到的坑很 ...
- Swift5 语言指南(二十一) 嵌套类型
通常创建枚举以支持特定类或结构的功能.类似地,定义纯粹在更复杂类型的上下文中使用的实用程序类和结构可能是方便的.为此,Swift允许您定义嵌套类型,从而在它们支持的类型定义中嵌套支持枚举,类和结构. ...
- tcpdf中增加微软雅黑的正确方式
找了很多增加字体的方式,不过提供的命令行下增加字体的命令是错误的,下面这个命令是验证过可以用的,不管是win还是linux活着mac都可以. tcpdf对中文的支持就不太好, 当然也可以支持, 比如里 ...
- Win + Manjaro 双系统、双硬盘安装方法 正确引导系统方法 黑屏解决方法(不瞎写,百分百有用)
1. 前言 本教程只涉及 Win + Manjaro 双系统.双硬盘安装过程中的核心要点,不涉及具体步骤,不注意这些要点,安装之后是进不去 Manjaro 系统的. 详细的安装步骤网上已经有很多了,这 ...
- iOS正确解决隐藏导航栏后push和pop或dismiss和present闪黑问题
情景: 一级页面不显示导航栏 ,二级页面显示导航栏. 方法一 适用于push/pop: 一级页面中 - (void)viewWillAppear:(BOOL)animated { [super vie ...
- PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析
Python黑帽编程1.5 使用Wireshark练习网络协议分析 1.5.0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...
- Python黑帽编程 3.1 ARP欺骗
Python灰帽编程 3.1 ARP欺骗 ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据 ...
- Python黑帽编程 3.3 MAC洪水攻击
Python灰帽编程 3.3 MAC洪水 传统的交换机(我只对我目前使用的交互机做过测试,按照常识只能这样表述)在数据转发过程中依靠对CAM表的查询来确定正确的转发接口,一旦在查询过程中无法找到相关目 ...
- 从“黑掉Github”学Web安全开发
Egor Homakov(Twitter: @homakov 个人网站: EgorHomakov.com)是一个Web安全的布道士,他这两天把github给黑了,并给github报了5个安全方面的bu ...
随机推荐
- VMware Network Adapter VMnet1和VMnet8 未识别的网络的解决方法
VMware Network Adapter VMnet1和VMnet8 被防火墙认定为未识别的网络,阻隔,无法使用端口映射,虚拟机的80端口无法传入,数据包只能出不能入.且公用网络被限制不能修改为家 ...
- 【转】预装(push)lib64中so文件查找错误
原文网址:http://blog.csdn.net/caroline_wendy/article/details/43615361 Android系统已经升级为64位系统,在进行预装(adb push ...
- vs2008包加载失败
由于安装vs2008sp1后,新建项目报错,解决未遂,于是重装vs2008,装完后又出现包加载失败问题: Microsoft.Data.Entity.Design.Package.MicrosoftD ...
- Delphi动态调用Java的WebService 转
Delphi动态调用Java的WebService —— 基于“Axis2发布WebService例子(HelloWorld)” uses ComObj; var WsObject: Variant; ...
- Permutations 解答
Question Given a collection of numbers, return all possible permutations. For example,[1,2,3] have t ...
- Linux中open函数以及退出进程的函数
open函数的flag详解1 读写权限:O_RDONLY O_WRONLY O_RDWR (1)linux中文件有读写权限,我们在open打开文件时也可以附带一定的权限说明 (譬如O_RDONLY就表 ...
- WPF - XAML如何引入名字空间
WPF 的XAML引入名字空间的概念,经常容易让人混淆.如何引入名字空间,并且在XAML中调用其中的类,下面给一个简单的介绍. 比如我们有一个Hepler类. namespace Wheat.PIMS ...
- 万恶DevExpress
公司需要,开始了DevExpress的学习之旅,说它万恶也只是在不了解它的情况下,熟悉之后能很方便的实现很多想要的功能 这里简单写一下要整理的内容,也就是大纲,以后再慢慢添加 一.控件和组件 date ...
- iOS中自动释放问题?
--前言:iOS开发中关于对象的释放问题,虽然知道规则,但总不清楚自动释放的对象什么时候彻底消失?它存在的多久?什么情况会消失?都不清楚,每次用自动释放对象,总有点心虚的感觉,以下是一些例子.研究. ...
- 实战ffs函数
这个函数是返回整形的最低位1的位置 自己写是这个样子的: /* Find the first bit set in I. */ int lx_ffs(int i) { int index = 0, r ...