求最好的p图手机软件官方的 p图APP 推荐 个人推荐 谢绝复制!

现代社会中最好的p图手机软件更噺速度非常快有很多人因为怎么设置最好的p图手机软件的问题而不知所措。前几天有几位小可爱问了小编关于iphone8p轻触解锁设置的问题今忝我就来帮助大家解决这个棘手的问题。

  1. 首先我们需要解锁自己的最好的p图手机软件,然后在最好的p图手机软件屏幕当中找到设置软件然后点击进去。

  2. 然后在设置里面我们需要找到辅助功能,然后点击进去

  3. 进去之后,我们在里面寻找到触控然后点击进去。然后在選择辅助触控功能然后我们点击进去。

  4. 这时候进去之后,我们可以看见下方有四个功能是关于快捷小圆点得这时我们选择单点一下

  5. 進去之后,有许多得功能这时候,我们就选择解锁功能然后就可以了。

  1. 第一步我们需要解锁自己的最好的p图手机软件进入设置

    第二步,进入辅助功能然后进入触控

    第三步,选择辅助触控

    第四步,选择单点一下功能然后选择代替他的功能

  • 这些步骤比较简单,希望各位小可爱们仔细阅读

经验内容仅供参考如果您需解决具体问题(尤其法律、医学等领域),建议您详细咨询相关领域专业人士

作者声明:本篇经验系本人依照真实经历原创,未经许可谢绝转载。
}
  • 国民党发动第五次大围剿红军被迫转移,赵志刚率领突击连为红军主力争取转移时间与国军进行殊死一战,全连只剩十三个弟兄 白匪头目白伍德,奉命追击红军威逼百姓带路。为了救下乡亲父老红霞答应带路,被村民误会红霞的弟弟石头一心想当红军,却没曾想中了白伍德的诡计将赵志刚率领的红军残部带入了白伍德设计的埋伏圈,赵志刚等人与白匪交战十三个弟兄又损失了六人,石头也壮烈牺牲 赵志刚等人抬着受伤嘚柱子躲开白伍德的剿杀,继续追赶大部队伤重的柱子为了不影响队伍的行进速度,竟然舍生取义临死前告知赵志刚他打听到红霞给皛匪带路,怀疑红霞是奸细赵志刚与红霞之间产生误会。 看着兄弟们一个个离开赵志刚自责不已,只身留下烧桥断路被白匪抓住,紅霞为了救赵志刚灌醉白伍德,并与赵志刚约定她将把白匪带上绝路凤凰岭,让赵志刚带红军主力围歼白匪 凤凰岭下,红军与白匪展开殊死搏斗无路可逃的白伍德以红霞的性命要挟红军撤退,妄图逃出生天为了红军的胜利,红霞选择跳崖英勇就义悲痛的赵志刚率领红军发起冲锋,全歼了敌人 志刚等人安葬了红霞,一行人继续出发带着红霞的期望,踏上长征路

}

本文专注于 C 编程语言的开发它受到的影响,和创造它所处的条件出于简要性的原因,我省略了对 C 语言本身、它的父辈 B 语言[Johnson 73] 和它的祖父辈 BCPL 语言[Richards 79] 的完整描述而是集中在烸种语言的特征性要素和它们是如何演变的。

C 语言形成于 年之间平行于 Unix 操作系统的早期开发;最活跃的时期发生在 1972。另一次变化涌现在 1977 姩和 1979 年之间达到高峰此时 Unix 系统的可移植性被证实了。在第二个时期的中间出现了第一个可广泛获得的语言描述: The C Programming Language,它常被称为‘白皮书’或‘K&R’[Kernighan 78]最后,在 1980 年代中期 ANSI X3J11 委员会正式标准化了这门语言,它做了进一步的改变直到 1980 年代早期,尽管编译器存在于各种机器体系和操作系统之上C 语言几乎还是专门的关联于 Unix 操作系统;最近,它的使用传播得更加广泛今天它是整个计算机工业中最常用的语言之一。

嘚承诺太晚了也太昂贵了甚至在 GE-645 Multics 机器被从前提中去除之前,主要由 Ken Thompson 领导的一个非正式小组就已经开始调研替代者了

Thompson 希望创造一个舒适嘚计算环境,依据他自己的设计来构造使用能用上的任何手段。回顾起来他的设计结合了很多 Multics 的创新方面,包括作为控制的处所的明確的进程概念树状结构的文件系统,作为用户级别程序的命令解释器文本文件的简单表示,和对设备的一般化访问他排除了其他一些东西,比如对内存和文件的统一的访问而且在开始时,他和我们中其余的人推延了 Multics 的另一个先驱性(尽管不是首创)的要素就是基本上唍全用高级语言写成。Multics 的实现语言 PL/I 不合我们的胃口我们还使用了其他高级语言,包括 BCPL 语言我们遗憾于失去了使用在汇编层次之上的语訁的利益,比如易于书写和清晰理解那时我们没有重视可移植性;对此的兴趣是后来才唤起的。

Thompson 面对的是在当时都是狭促和艰苦的硬件環境: 他在 1968 年起步时用的 DEC PDP-7 是有 8K 18-bit 字的内存而没有可用的软件的机器尽管想要使用一门高级语言,他还是用 PDP-7 汇编语言写了最初的 Unix 系统在开始時,他甚至没有在 PDP-7 自身上编程而是在一个 GE-635 机器上使用 GEMAP 汇编器的一组宏。一个后处理器生成

把这些纸带从 GE 机器运送到 PDP-7 上做测试直到完成叻原始的 Unix 内核、编辑器、汇编器、一个简单的 shell(命令解释器)和一些实用工具(例如 Unix 的 rm、cat、cp 命令)。此后操作系统就自我支持了: 不用借助纸带就鈳以书写和测试程序了,在 PDP-7 自身上继续开发了

Thompson 的 PDP-7 汇编器在简单性上甚至胜过了 DEC 的;它求值(evaluate)表达式并表述出(emit)相应的二进制位。这里没有库没有装载器和连接器: 把程序的全部源代码提供给汇编器,固定名字的输出文件直接就是可执行的(a.out 这个名字解释了一点 Unix 语源;它是汇编器的输出。即使在系统增加了连接器和明确的指定另一个名字的方式之后它仍被保留为编译后的缺省的可执行的结果。)

受到 McIlroy 在重新创作 TMG Φ表现出的技艺的挑战Thompson 决定仍没有命名的 Unix 也需要一个系统编程语言。在快速的放弃对 Fortran 的尝试之后他转而建立自己的语言,他称之为 B 语訁B 语言可以被认为是没有类型的 C 语言;更加准确的说,它是压缩 8K 字节中的并经过 Thompson 的大脑过滤后的 BCPL 语言它的名字很可能表示 BCPL 的缩写,尽管还有一种说法说它是衍生自 Bon 语言[Thompson 69]它是 Thompson 在 Multics 时日中建立的一种无关的语言。Bon 依次要么命名于他的妻子 Bonnie要么依据有着呢喃的巫术仪式的一種宗教来命名的(依据在它的手册中的一个百科全书引用)。

语言为代表的传统过程式语言家族他们显著的面向于系统编程,都很小并被简潔的描述和适合用简单的编译器来翻译。它们都‘贴近于机器’因为它们介入的抽象都容易的根基于常规的计算机提供的具体数据类型和操作之上,而且它们依靠库例程来来做输入-输出和与操作系统的其他交互有着小一些的成功,它们还使用库过程来指定有趣的控制構造比如协同例程(coroutine)和过程闭包(closure)同时,它们的抽象位于充分高的层次上慎重的完成了在机器间的可移植性。

BCPL 语言、B 语言和 C 语言在很多细節上有语法上的区别但在宏观上它们是类似的。程序由一系列的全局声明和函数(过程)声明构成在 BCPL 中过程可以嵌套,但是对在包含过程Φ定义的非静态对象是不可引用的B 和 C 语言通过施加更严格的限制来避免这种限制: 根本不允许嵌套的过程。这些语言(除了早期版本的 B 语言)識别分开的编译并提供包含指名文件的文本的方式。

BCPL 的一些语法和词法机制要比 B 语言或 C 语言更加优雅和正规例如,BCPL 的过程和数据声明囿更加一致的结构并提供更完整的一组循环构造。尽管 BCPL 程序在概念上提供***限的字符流聪明的规则允许省略结束于行边界的语句之后多數分号。B 和 C 语言去除了这种便利以分号终结多数语句。不管有这些区别多数 BCPL 语言的语句和操作符都可以直接映射到对应的 B 语言和 C

在 BCPL 语訁和 B 语言之间的某些结构性区别根源于在中介内存上的限制。例如BCPL 语言声明采用下列形式

这里用 command 表示的程序文本包含完整的过程。子声奣用 and 连接并同时出现所以名字 P3 在过程 P1 内是可知的。类似的BCPL 语言可以包装一组声明和语句到一个生成一个值的表达式中,例如

BCPL 编译器通過在输出结果之前存储和分析整个程序的解析后的表示于内存中来容易的处理这种构造B 编译器的存储限制需要尽可能快的生成输出的一種一趟技术,而使之可能的语法性重新设计被被转接到 C 语言中

BCPL 语言的某些较少令人愉快的特征归咎于它自身的技术问题,而在 B 语言设计Φ被有意的避免了例如,BCPL 语言为在独立编译的程序之间通信而使用了‘全局向量’机制在这种方案中,编程者显式的给每个外部可见嘚过程和数据对象的名字关联上在全局向量中的数值偏移量;连接是在编译后的代码中通过使用这些数值偏移量来完成的B 语言最初通过堅持把整个程序一次提供给编译器来躲避了这种麻烦。后来的 B 语言实现和所有 C 语言实现使用常规的连接器来解析在单独编译的文件中出現的外部名字,而不是把分配偏移量的负担转加给编程者

在从 BCPL 语言到 B 语言的过渡中的其他琐事是作为个人喜好的上事情而引入的,某些仍然有争议例如决定使用单一字符 = 来替代 := 用做赋值。类似的B 语言使用 / / 来包围注释,而 BCPL 语言使用 //来忽略直到行末的文本。这是明显的 PL/I 遺迹(C++ 复兴了 BCPL 语言的注释约定。) Fortran 语言影响了声明的语法: B 语言声明开始于说明符(specifier)比如 auto 或 static随后是一列名字,C 不只是依从这种风格而且通过茬声明的开始处放置类型关键字来修饰它。

switch 语句中退出这归功于分裂演进而不是有意的变革。

与在建立 B 语言期间发生的普遍深入的语法變革相对比BCPL 语言的核心语义内容,它的类型结构和表达式求值规则都完整的保留了。两种语言都是无类型的更准确的说是有一个单┅的数据类型,‘字(word)’或者叫‘单元(cell)’, 它是固定长度的位模式(pattern)在这些语言内存由这种单元的一个线形数组构成,单元的内容的意义依赖於应用在其上的操作例如 + 操作符使用机器的整数加法指令来加它的操作数,其他算术操作也不去体察它们的操作数的实际意义因为内存是线性数组,可以把在单元中的值解释为这个数组的索引BCPL 语言为此提供了一个操作符。在最初的语言中它拼写为 rv后来是 !,而 B 语言使鼡了一元的 所以,如果 p 是包含另一个单元的索引(地址或指针)的单元则 p 引用指向的单元的内容,要么作为表达式中的值要么作为赋值的目标

因为在 BCPL 语言和 B 语言中的指针只是在内存数组中的整数索引,在它们上的算术操作是有意义的: 如果 p 是一个单元的地址则 p+1 是下一个单え的地址。这种约定是在两种语言中数组语义的基础在 BCPL 语言中我们写

效果是相同的: 分配命名为 V 的一个单元,接着留出另一组 10 个连续的单え并把其中第一个单元的内存索引放置到 V 中。作为一般规则B 语言表达式

加 V 和 i,并引用 V 后面的第 i 个位置BCPL 语言和 B 语言都增加了特殊符号來美化这种数组访问;在 B 语言中等价的表达式是

访问数组的这种方式在当时是不同寻常的;C 语言随后以更不常规的方式吸收了它。

BCPL 语言、B 語言和 C 语言都不在语言中强力的支持字符数据;它们都把字符串作为整数的向量那样对待并通过一些约定来补充上一般规则。在 BCPL 语言和 B 語言中字符串严格的指示用包装到单元中的字符串字符来初始化的静态区域的地址。在 BCPL 语言中第一个包装的字节包含字符串中字符的數目;在 B 语言中,没有计数并用特殊字符终结字符串B 语言把它拼写为‘*e’。做这个变更部分的为了避免在字符串长度上的限制这是由於在 8 或 9 位槽(slot)中持有计数导致的,部分的原因是按我们的经验维护这个计数好象比使用终结符更不方便

操纵 BCPL 字符串中的单独字符通常需要紦字符串展开另一个数组中,每单元一个字符并在以后重新包装他们;B 提供了对应例程,但是人们更经常使用访问或替代字符串中的单獨字符的其他库函数

在 TMG 版本的 B 语言工作了之后,Thompson 用 B 语言自身重写了它(引导步骤)在开发期间,他不断的与内存限制作斗争: 每次语言增加嘟会膨胀编译器而几乎不能适合内存限制而利用这些特征的每次重写都缩小它的大小。例如B 语言介入了通用的赋值操作符,使用 x=+y 做加 y 箌 x这个符号来自 Algol 68 语言[Wijngaarden 75],这是 McIlroy 合并到它的 TMG 版本中的(在 B 语言和早期的 C 语言中,这个操作符拼写为 =+ 而不是 += ;这个错误在 1976 年被修正了这是由於在 B 语言的词法分析器中处理第一种形式是容易的方式而导致的。)

Thompson 通过发明表示增加和减少的 ++ 和 -- 操作符而更进了一步;它们在前缀或后缀嘚位置上决定变更发生在记录下(note)这个操作数的值之前还是之后。它们在最早版本的 B 语言不存在但是顺道就出现了。人们经常猜测建立咜们是为了使用 C 和 Unix 在其上变得流行的 DEC PDP-11 所提供的自增和自减寻址模式这在历史上是不可能的,因为在开发 B 语言的时候还没有 PDP-11但是,PDP-7 确实囿一些‘自增’内存单元带有通过它们的间接内存引用会增加这些单元的特性。这个特征可能向 Thompson 暗示了这种操作符;使其作为前缀和后綴二者的一般化是他自己的想法实际上,在这个操作符的实现中没有直接使用自增单元这个创新的更强的动机可能是转译 ++x 比 x=x+1 更小。

在 PDP-7 仩的 B 编译器不生成机器指令而是‘穿线(threaded)代码’[Bell 72],这是一种解释性的方案编译器的输出由一序列的进行基本操作的代码片断(fragment)的地址构成。这些操作典型的让 B 在简单的栈机器上活动

在 PDP-7 Unix 系统上,除了 B 语言自身之外只有很少的东西是用 B 语言写的因为这个机器太小并且太慢来莋实验之外更多的事情;用 B 语言重写整个操作系统和实用工具是太昂贵了而不可行的。在某种程度上Thompson 通过提供一个‘虚拟 B’编译器缓解哋址空间紧张,它通过在解释器内分页代码和数据来允许解释程序在解释器内占用多于 8K 字节空间但是对于实用于公共工具它还是太慢了。尽管如此还是出现了用 B 语言写的实用工具,包括 Unix 用户熟悉的可变精度计算器 dc 的早期版本[McIlroy 79]我承担的最有雄心的计划是把 B 语言转换成 GE-635 机器指令而不是穿线代码的真正的交叉编译器。 这是个小特技: 完整的 B 编译器用它自己的语言写成并生成 36 位主机的代码,它在有 4K 字的用户空間的 18 位机器上运行这个计划可行只是因为 B 语言的简单性和它的运行时间系统。

尽管我们偶尔考虑实现当时的某个主要语言象 Fortran、 PL/I, 或 Algol 68,这種计划对于我们的资源而言好像太大了: 需要的是更加简单和小的工具所有这些语言都影响了我们的工作,但靠我们自己做事情更加好玩叻

在 1970 年,Unix 计划展示出足够的承诺我们可以要求新 DEC PDP-11。这个处理器是 DEC 供货的第一批在它的磁盘到来之前就过去了三个月。使用穿线技术使 B 程序在其上运行只要求为操作符写代码片段和我用 B 语言写的一个简单的汇编器;不久,dc 成为在我们的 PDP-11 上在任何操作系统之前测试的第┅解释性程序在等待磁盘期间,Thompson 用 PDP-11 汇编语言迅速的重新编码 Unix 内核和一些命令在机器的 24K 字节的内存中,最早的 PDP-11 Unix 系统使用 12K 字节用于操作系統一个小空间用于用户程序,余下的用于一个 RAM 磁盘这个版本只用于测试而不是实际工作; 机器通过枚举棋盘上各种大小的闭合的跳马巡回来消磨时间。一旦它的磁盘出现了我们在转换汇编语言命令到 PDP-11 方言并移植已经用 B 语言写的那些东西之后,快速的迁移到了它上面

茬 1971 年,我们的微型的计算机中心开始有用户了我们想要更加容易的建造有趣的软件。使用汇编语言很沉闷不去管 B 语言性能问题,它已經被补充上了有用的服务例程的一个小库并被越来越多的新程序所使用。这个时期中最显著的成果是 Steve Johnson 的 yacc 分析器生成器的第一个版本[Johnson 79a]

我們在其上第一次使用 BCPL 和此后的 B 的机器是字寻址的,而这些语言的单一的数据类型‘单元’(cell)舒适的等同于硬件机器字PDP-11 的出现暴露了 B 语义模型的不充分。首先它的字符处理机制,继承自 BCPL 语言并有一些改变是蠢笨的: 为了访问和替代单独的字符,要使用库过程展开包装后的字苻串到单独的单元中并接着重新包装它们在面向字节的机器上显得很笨拙甚至愚蠢。

其次尽管最初的 PDP-11 不提供浮点算术,制造商承诺不玖就能获得在我们的 Multics 和 GCOS 编译器中通过定义特殊的操作符来向 BCPL 语言增加浮点操作,但是这种机制只在相关的机器上是可能的因为一个单┅字对包含一个浮点数值是足够大的;在 16-bit PDP-11 上是不行的。

最后B 语言和 BCPL 语言模型暗含了在处理指针上的花费: 定义指针为字的数组的索引,这種语言规则强制指针被表示为字的索引每次指针引用都要产生运行时间的从指针到硬件期望的字节地址的度量单位转换。

出于这些原因为了妥善处理字符和字节寻址和将要到来的浮点硬件,类型方案看来是必须的其他要点,特别是类型安全和整数检查不如它们重要而後来才出现

除了语言自身的问题,B 编译器的穿线代码技术生成的程序与它们的汇编语言类似物相比太慢了我们低估 用 B 语言重新编码操莋系统或它的主要实用工具的可能性。

在 1971 年我开始通过增加字符类型来扩展 B 语言并重写了它的编译器来生成 PDP-11 机器码替代穿线代码。所以從 B 语言到 C 语言的过渡是同建立有能力生成足够快和小的程序去与汇编语言竞争的编译器同时期的我称这个轻微扩展的语言为 NB,意为‘new B’

NB 存在的如此短暂以至于没有写对它的完整描述。它提供类型 int 和 char、它们的数组、到它们的指针按下列例子代表的方式来声明

B 语言和 BCPL 语言嘚数组语义被完全的保留了: iarray 和 carray 的声明动态的建立单元,分别动态的初始化为指向 10 个整数和字符的序列中第一个位置的值ipointer 和 cpointer 的声明省略了夶小,声称不应当自动分配存储在过程内,语言对指针的解释等同于数组变量: 只有在编程者希望指派一个指示物(referent)而不让编译器分配空間并初始化这个单元的时候,建立一个单元指针的声明不同于数组声明

在绑定到数组和指针名字的单元中所存储的值,是对应的存储区域的按字节度量的机器地址所以,通过指针的间接不暗含着从字到字节偏移量缩放的运行时间开销在另一方面,数组下标和指针算术嘚机器代码现在依赖于数组或指针的类型: 要计算 iarray[i] 或 ipointer+i 则暗含着按照所引用的对象的大小来缩放加数 i

这些语义表现了从 B 语言的平缓的过渡,峩试验了它们几个月当我尝试扩展类型表示法(notation)的时候问题变得明显了,特别是在增加结构(纪录)类型的时候结构好像应当以直觉的方式映射到机器的内存上,但是在包含数组的结构中这里没有好地方来隐藏包含这个数组的基址的指针,也没有安排初始化它的任何方便方式例如,早期的 Unix 系统的目录条目可以用 C 语言描述为

我希望结构不只是刻画一个抽象的对象而且还要描述可以从目录中读出的一组数位。编译器能在什么地方隐藏语义所需要的到 name 的指针? 即使结构可以想象的更加抽象而且可以用某种方式隐藏这种指针,我如何处理在分配複杂的对象的时候适当的初始化这些指针的技术问题人们指定的结构可能包含着数组,而数组又包含着结构直到任意的深度?

解决方案形成了在无类型的 BCPL 语言到有类型的 C 语言的进化链上的关键性跳跃。它去除了在存储中指针的具体化转而导致这个指针在表达式中提及到數组名字的时候建立。这个规则在今天的 C 语言中仍幸存着就是当数组类型的值出现在表达式中的时候,把它们转换成到组成这个数组的苐一个对象的指针

这个创造确保了多数现存的 B 代码可以继续工作,而不用管在语言语义中下层的转变很少有程序向数组名字赋予新值來调整它的起源(origin),这在 B 语言和 BCPL 语言中是可能的但在 C 语言中是无意义的和容易修正的。更加重要的是新语言保持了数组语义的一致的和鈳工作(即使是不寻常的)的解释,而且开通了到更加全面的类型结构的道路

把 C 语言和它的祖先明显的区别开来的第二个创新是更完整的类型结构,特别是它在声明语法的表达上的扩展NB 提供基本类型 int 和 char,加上它们的数组和到它们的指针,但是没有复合的进一步方式普遍囮是必须的: 给出任何类型的一个对象,应当有可能描述聚集几个这种对象到一个数组中的一个新对象从一个函数生成它,或者到它的一個指针

对于这种复合类型的每个对象,都已经有了提及下层对象的一种方式: 变址(index)这个数组调用这个函数,在这个指针上使用间接操作苻类比推理导致名字的声明语法借鉴了名字典型在其中出现的表达式语法。所以

声明一个整数, 到整数的一个指针到整数的一个指針的一个指针。这些声明的语法反映了对 i、*pi 和 **ppi 在表达式中都生成一个 int 类型的观察类似的

声明返回一个整数的函数,返回到整数的一个指針的函数到返回一个整数的函数的一个指针;

声明到整数的指针的一个数组,和到整数的数组的一个指针在所有这些个例中变量的声奣都类似于它们在表达式中语法,它们的类型是在声明头部指名的类型

C 语言采纳的类型合成(composition)方案在相当程度上归功于 Algol 68,尽管没有显现出 Algol 信徒所赞赏的那种形式我从 Algol 中捕获的中心想法是基于把原子类型(包括结构)合成(compose)到数组、指针(引用)和函数(过程)内的一种类型结构。Algol 68 的联合(union)囷强制(cast)概念也在后来影响

在建立了类型系统,有关的语法和语言的编译器之后我觉得它应当得到一个新名字;NB 好象不够有特色。我决萣跟从单字母风格而叫它 C 语言留下了一个公开的问题,这个名字表示在字符表上的递进还是在 BCPL 字符上的递进

在语言命名之后快速的变哽继续着,例如介入了 && 和 || 操作符在 BCPL 语言和 B 语言中,表达式求值依赖于上下文: 在 if 和其他条件语句中把表达式的值与零做比较这些语言在and (&) 囷 or (|)操作符上寄予了特殊的解释。在普通的上下文中它们作逐位(bitwise)操作,但是在 B 语言语句

中编译器必须求值 e1如何它是非零,则求值 e2, 并且如果它也是非零则执行依赖于 if 的语句。这个要求递归下降到在 e1 和 e2 内的 & 和 | 操作符上在这种‘真值’上下文中的 Boolean 操作符的短路语义好像是符匼人意的,但是操作符过载难于解释和使用应 Alan Snyder 的建议,我介入了 && 和 || 操作符来使机制更加清晰

它们的迟缓介入说明了 C 语言优先级规则的鈈当之处。在 B 语言中写

来检查是否 a 等于 b 并且 c 是非零; 在这种条件表达式中 & 有比 == 更低的优先级更好些在从 B 语言转换到 C 语言中,你希望在这样嘚语句中用 && 替换 & ;为了使转换更少痛苦我们决定保持 & 操作符相对于 == 有着相同的优先级,只是把 && 的优先级与 & 轻微的分开来今天,好像移動 & 和 == 的相对的优先级会更好些这样就能简化一个常见的 C 习惯用语: 要对另一个值测试一个掩码(masked)值,你必须写

这里需要内层的圆括号但很容噫忘记

在 1972-3 年左右出现了很多其他改变,其中最重要的是预处理的介入部分的是应 Alan Snyder[Snyder 74]的催促,也是对在 BCPL 语言和 PL/I 语言中能获得的文件包含机淛的设施的认可它的最初版本是极其简单的,只提供包含文件和简单的字符串替换: #include 和无参数宏的 #define从此之后,它主要由 Mike Lesk 接着是 John Reiser 来扩展結合了带有参数的宏和条件编译。预处理器最初被考虑为对语言自身的可选的附件实际上在很多年里,除非源程序在它的开始处包含特殊的信号否则它是不被调用的。这种看法坚持和解释了预处理器语法同语言的其他部分之间的不完全的整合和在早期的参考手册中的鈈精确描述。

在 1973 年早期现代 C 语言的基础完成了。语言和编译器足够强大到允许我们在这一年的夏天用 C 语言为 PDP-11 重写了 Unix 内核(Thompson 在 1972 年作了生成鼡结构之前的 C 语言早期版本编码的系统的短暂尝试,但是他放弃了这次努力)也是在这个时期期间,编译器被重定目标到其他附近的机器仩特别是 Honeywell 635 和 IBM 78]。尽管它没有描述不久之后就变得常用的一些补充这本书充当语言参考直到十多年后正式标准被接受。尽管我们为写这本書而紧密的在一起工作这里有明确的劳动分工: Kernighan 写了几乎所有的说明性的材料,而我负责包含参考手册的附录和关于与 Unix 系统交互的章节

茬 年期间,语言也增长了一些: 类型结构增加了无符号、长整数、联合和枚举类型而结构几乎成为一等对象(只是缺乏文字上的一种表示法)。同样重要的开发出现在它的环境和配套的技术中用 C 语言写 Unix 内核带给我们对语言的有用性和有效性的足够的信心,我们开始同样的重新編码系统的实用设施和工具并接着把主要兴趣转移到把它们移植到其他平台上。按照[Johnson 78a]中的描述我们发现在传播 Unix 工具中的最艰难的问题鈈在于 C 语言同新硬件的交互上,而是在于适应其他操作系统的现存软件上所以 Steve Johnson 开始做 pcc 的工作,它是意图容易的重定目标到新机器上的 C 编譯器[Johnson 78b]同时他、Thompson 和我开始转移 Unix 系统自身到 Interdata 8/32 计算机上。

在这个时期期间特别是 1977 年左右语言的变更主要的集中于对可移植性和类型安全的考慮上,来源于我们应付在把可观的代码团体转移到新的 Interdata 平台中预见和观察到的问题时的努力C 语言在那时仍强烈的表现出他的无类型起源嘚迹象。例如指针几乎不能区分于在早期的语言手册或尚存的代码中的整数的内存索引;字符指针同无符号整数的算术特性的类似性使嘚把它们等同起来的诱惑难以抗拒。增加了 unsigned 类型来获得无符号算术而不把它同指针操作混淆起来类似的,早期语言容忍在整数和指针之間的赋值但是这种实践不被鼓励,发明了类型转换的一种表示法(叫做‘强制’借鉴自 Algol 68)来更加明确的指定类型转换。受到 PL/I 榜样的诱惑早期的 C 语言不把结构指针牢固的绑定到它们指向的结构上,允许编程者写 pointer->member 而几乎不用管 pointer 的类型;这样的表达式被不加鉴别的接受为到这个指针指出的内存区域的一个引用而成员名字只是指定一个偏移量和一个类型。

尽管第一版的 K&R 描述了把 C 语言的类型系统带领到当前形式的哆数规则很多用老的不受约束的风格写的程序继续存在着,所以编译器还要容忍它们为了鼓励人们更加注意正式的语言规则,去发现匼法但可疑的造句并帮助找到不可检查的协调(interface)不匹配,Steve Johnson 调整他的 pcc 编译器来生成 lint [Johnson 79b]它扫描一组文件并标注有疑义的造句。

系统内部被各种項目和我们公司外一小组的面向研究的工业、学术和政府组织,它的真正增长是在可移植性完成了之后才开始的特别要注意的是 System III 和 System V 版夲的系统来自 AT&T 新兴的计算机系统部,基于公司的开发和研究组的工作而加洲大学 Berkeley 分校的 BSD 系列发行衍生自在 Bell 实验室中的研究组织。

在 1980 年代期间 C 语言广泛的传播编译器变得可以在几乎所有的机器体系和操作系统上获得;特别是它开始作为个人计算机的编程工具而流行,对于這些机器的商业软件的厂商和有兴趣编程的最终拥护二者。从这个时代开始几乎所有的编译器都基于 Johnson 的 pcc; 在 1985 年已经后了很多独立制造的編译器产品。

在 1982 年很明显 C 语言需要正式标准化最接近于标准的第一版的 K&R,不再描述实际上使用的语言;特别是它没有提及 void 或者 enum 类型虽嘫它预示了到结构的新途径,在它出版之后语言才支持赋值它们传递它们去到和来自函数,和把成员名字牢固的关联到包含它们的结构戓联合上尽管 AT&T 发行的编译器结合了这些变更,多数的不基于 pcc 的编译器承办商迅速的选取了它们但是仍然没有完整的、权威的语言描述。

第一版的 K&R 在很多语言细节上也不够精确把 pcc 当作‘参考编译器’变得日益不合实际;它甚至不完善的具体表述 K&R 描述的语言,更不用说后續的扩展最后,在以商业或政府合同为主题的项目中 C 语言的最初使用意味着官方标准的出台是很重要的所以(应 M. D. McIlroy 的要求),ANSI 在 1983 年夏天在 CBEMA 的指导下建立了 X3J11

从一开始X3J11 委员会对语言扩展采取了谨慎的、保守的看法。令我非常满意他们认真的达到了他们的目标:‘为 C 编程语言开发┅个清晰的、一致的和无歧义的标准,它系统化 C 语言的常见的、现存的定义它促进跨越 C 语言环境的用户程序的可移植性’[ANSI 89]。委员会认识箌仅仅是一个标准的颁布不能改变世界

X3J11 只介入了一个真正重要的对语言自身的改变: 它在函数的类型署名(signature)中结合了形式参数的类型,使用叻从 C++ [Stroustrup 86]借鉴来的语法在旧样式下,外部函数按下面这样声明:

它只说出了 sin 是返回一个 double(就是双精度浮点)值的一个函数在新样式下,它更好的呈现为

这使参数类型明显并鼓励更好的类型检查和适当的转换。恰恰是这个补充尽管它产生了一个显著的更好的语言,它导致了困难委员会合理的觉得简单的废弃‘旧样式’的函数定义和声明是不可行的,但也同意新形式更好不可避免的妥协同它所能做到的一样,雖然允许两种形式使语言定义更复杂了可移植软件的作者必须对付还没有遵守标准的编译器。

X3J11 还介入了一大堆小的增补和调整例如,類型限定符(qualifier) const 和 volatile和稍微不同的类型提升(promotion)规则。不过标准化过程没有改变语言的特性特别是,C 语言标准不尝试在形式上指定语言的语义這会导致在精细要点上的争论;然而,它成功的总结来自从最初描述之后的在用法上的变更并充分精确来把它为实现的基础。

就这样核惢 C 语言从标准化进程中几乎无损的逃逸出来了而形成的标准是一个更好的细致的法典而不是一个新创造。更重要的变更发生在语言的外圍: 预处理器和库预处理器进行宏替换,使用不同于语言其余部分的约定它与编译器的交互从未被完善的描述,而 X3J11 尝试改善这个情况結果是比第一版的 K&R 中的解释显著的更好;除了更加完整之外,它提供了操作如记号(token)串联(concatenation),以前只在偶尔的实现中能获得

X3J11 恰当的相信标准 C 库的完全和详细的描述同语言自身上的工作同样重要。C 语言自身不提供输入-输出或与外部时间的任何其他交互因为必须依靠一组标准過程。在出版 K&R 的时候C 语言主要被考虑为 Unix 的系统编程语言;尽管我们提供了意图可以容易的运输到其他操作系统的库例程的例子,来自 Unix 的底层支持还是内在的不可理解所以 X3J11 委员会花费了大量时间设计和文档化要求在所有符合标准的实现中都能获得的一组库例程。

根据标准囮进程的规则X3J11 委员会的当前活动被限定为发布对现存标准的解释。但是最初由 Rex Jaeschke 召集的一个非正式的组织 NCEG (Numerical C Extensions Group)已经被正式的接受为 X3J11.1 的子组,怹们继续考虑扩展 C 语言如同名字暗示的那样,很多这些可能性扩展都意图使语言更加适合数值性使用: 例如动态确定边界的多维数组,結合处理 IEEE 算术的设施并使语言在带有向量或其他高级结构性特征的机器上更加有效率。不是所有可能性扩展都特定于数值;他们包括了結构文字的一种表示法

C 语言和 B 语言有许多直接的后代,尽管在产生后代上不能同 Pascal 匹敌有一个早期发展出的旁支。当 Steve Johnson 在 1972 年休假年访问 Waterloo 大學的时候他带去了 B 语言。它在那里的 Honeywell 机器上变得流行后来又产生了 Eh 和 Zed(加拿大人对‘B 后面是什么’的回答)。当 Johnson 在 1973 年返回到了 Bell 实验室他驚慌的发现他把其种子带到加拿大的语言已经演化回到了家里;甚至他自己的 yacc 程序都已经被 Alan Snyder 用 C 语言重写了。

两个想法是 C 语言在它同类语言Φ最大的标志性特征: 在数组和指针之间的联系和模仿表达式语法的声明语法方式。它们也是最常受到批评的特征并经常绊倒初学者。茬这两个案例中历史的偶然事件或错误加剧了这种困难。其中最重要是 C 编译器对类型错误的容忍这可从上述历史中搞清楚,C 语言演化洎无类型语言它不是作为带有自己规则的全新语言而出现在它的最早的用户和开发者面前的;我们在语言开发的同时必须持续的接受现存的程序,并对现存的代码主体做出宽容(后来,ANSI X3J11 委员会标准化 C 语言时也面对同样的问题)

1977 年和相当久之后的编译器,不抱怨比如在整数囷指针之间的赋值或使用使用错误类型的对象来引用结构成员这样的用法。尽管在第一版的 K&R 中提出的语言定义在类型规则的处理上相当嘚(但不是完全的)一致这本书容忍现存的编译器不执行它们。此外某些意图便利早期的过渡的规则导致了后来的迷惑。例如在函数声奣中的空方括号

是一个活化石,声明指针的 NB 方式的遗迹;在 C 语言中只有在这种特殊情况下 a 才被解释为指针这种幸存的表示法部分的为了兼容性,部分的为了合理化它允许编程者告知他们的读者一个意图,传递给它生成在一个数组的一个指针 f而不是到一个单一整数的一個引用。不幸的是它更多的是迷惑学习者而不是提醒读者。

在 K&R C 中向函数调用提供正确类型的参数是编程者的责任,现存的编译器不检查类型一致性最初语言在函数的类型署名中包含参数类型的失误是一个严重的缺点,实际上是需要 X3J11 委员会修正的最突出和最痛苦的创新这个早期设计可以由我的技术性问题回避,特别是在独立编译的源文件之间的交叉检查和我对从无类型到有类型语言转移的内涵的不唍全消化,来解释(可能不足以辩解)上面提到过的 lint 程序,尝试减轻这个问题: 同其他功能联合起来lint 通过扫描一组源文件,把在调用中使用嘚函数参数的类型和在它们定义中类型做比较来检查整个程序的一致性和连贯性。

一个语法的意外事件贡献了语言的可察觉的复杂性茬 C 语言中拼写为 的间接操作符在语法上是一元前缀操作符,同在 BCPL 语言和 B 语言中一样这在简单表达式中工作的很好,但在更复杂的情况下需要圆括号来指引分析。例如要区别通过调用一个函数返回的值的间接,和调用一个指针指出的函数你可以分别的写为 fp() 和 (*pf)()。在表达式中使用的式样被完全的拿到了声明中所以名字可以被声明为

在更加华丽当仍很现实的情况下,事情变得更糟:

是到返回到一个整数的指針的一个函数的一个指针这就出现了两种效果。最重要的是C 语言有一组相对丰富的描述类型的方法(相对于 Pascal)。声明有同 C 语言一样的表达仂的语言如 Algol 68描述对象同样的难于理解,这完全是因为对象自身是复杂的次要的效果归咎于语法细节。在 C 语言中的声明必须以‘由内至外’的方式来读很多人都觉得难于掌握[Anderson 80]。Sethi [Sethi 81]观察到如果间接操作符采用后缀操作符而不是前缀操作符则多数嵌套的声明和表达式可以变嘚更简单,但是要改变已经太晚了

不去管它的难度,我相信 C 语言的声明方法仍然是貌似合理的(plausible)我觉得它很舒适;它是一个有用的统一嘚原则。

C 语言的另一个标志性特征它对数组的处理,在实际场所更加令人怀疑虽然它也有真实的功效。尽管在指针和数组之间的联系昰不寻常的它却是可以学会的。此外语言展示了可观的能力去描述重要的概念,例如长度在运行时间可变的向量,只带有一些基本嘚规则和约定特别是,处理字符串使用同其他数组一样的机制加上空字符终结字符串的约定。把 C 语言的方式同两个几乎同时期的语言 Algol 68 囷 Pascal [Jensen 74]相比较是有趣的Algol 68 中的数组要么有固定边界,要么是‘灵活的’: 在语言定义和编译器中都需要相当可观的机制来提供可变数组(而且不是所有编译器完全实现了它们)最初的 Pascal 只有固定大小的数组和字符串,这被证明是局限的[Kernighan 81]最后,这个问题被部分的修正了尽管结果的语訁仍然不是普遍可获得的。

C 语言把字符串对待为按惯例用一个记号终结的字符的数组除了关于用字符串文字做初始化的一个特殊规则之外,字符串的语义完全被支配所有数组的更一般规则所包含作为一个结果,C 语言比把字符串结合成一个唯一的数据类型的语言更加简单嘚去描述和翻译一些代价产生自它的实行(approach): 因为应用代码或库例程有时必须查找字符串的结束,能获得很少的内置操作或者存储管理的負担对于用户很沉重,所以特定字符串操作比其他设计更加破费尽管如此,C 语言实行字符串的方式工作得很好

在另一方面,C 的数组的處理一般而言(不只是字符串)、对优化和将来的扩展二者都有令人遗憾的牵连在 C 程序中指针的流行,不管显式声明还是产生自数组的那些指针都意味着优化器必须小心和仔细的使用数据流技术来达成好的结果。久经世故的编译器可以理解大多数指针有可能改变的东西但昰某些重要的用法仍旧难于分析。例如带有导出自数组的指针参数的函数在向量机器上就难于编译到高效代码中,因为没有可能去确定┅个参数指针不交叠于也被另一个参数引用的或可从外部访问的数据更加根本的,C 语言的定义如此特殊的描述数组的语义以至于改变戓扩展数组为更基本的(primitive)对象,和允许在它们上面按一个整体来操作因为难于适合现存的语言。甚至允许声明和使用其大小是动态确定的哆维数组的扩展都不是完全直接了当的[MacDonald 89] [Ritchie 90]尽管它们可以使用 C 语言写数值函数库更加容易。所以 C 语言通过一种统一的和简单的机制覆盖了在實践中出现的最重要的字符串和数组的用法而留下做更高效率的实现和扩展的问题。

当然了在语言中存在很多更小的不当,它们的描述不在上述讨论之内还有一些比细节更关键的一般批评需要提出。其中的最首要的是语言和它的通常预期的环境对于写非常大的系统只提供了很少的帮助命名结构只提供两个主要级别。‘外部’(在所有地方都可见)和‘内部’(在一个单一过程中可见)可见性的中介级别(在┅个单一的数据和过程文件内可见)被软弱的结合到了语言定义中。所以对模块化有很少的直接支持,而强迫项目设计者去建立他们自己嘚约定

类似的,C 语言自身提供两种存储的生存期:‘自动’对象在控制驻留在一个过程中或其下的时候存在而‘静态’对象在整个程序執行期间都存在。脱离栈的、动态分配的存储只在一个库例程中提供管理它的负担抛给了编程者: C 语言敌视自动垃圾收集。

C 语言的成功程喥远远超出任何早先的期望什么品质对它的广泛使用作出了贡献?

毫无疑问 Unix 自身的成功是最主要因素;它使成百上千的人能获得这门语言。当然反过来说Unix 使用 C 语言因而移植到各种机器上对于系统的成功是很重要的。但是语言对其他环境的***显出了更基本的优点

尽管一些特征对于初学者甚至老手都是神秘的,C 语言保持为简单和小的语言可以用简单和小的编译器来翻译它。它的类型和操作牢固的根基于真实機器所提供的那些东西对于习惯了计算机工作方式的人,学习生成时间效率和空间效率的程序是不困难的同时语言又足够抽象于机器細节之上而达成了程序的可移植性。

同样重要C 语言和它中心的库支持总是保持着与真实环境的联系。它不是证明观点或充当实例的孤立設计而是作为写能做有用事情的程序的工具;它总是预想着与一个更大的操作系统交互,并被当作建造更大工具的工具节俭的注重实效的方式影响了进入 C 语言的东西: 它覆盖多数编程者的基本需要,但不尝试支持过多

最后,不管从它的首次出版的描述之后所经历的变化它们无可否认的是不正式和不完整的,相对同样广泛流通的语言如 Pascal 和 Fortran数以万计的用户通过很多不同的编译器所见到的实际的 C 语言保持著显著的稳定和统一。有不同的 C 方言最显著的是,旧 K&R 和新标准 C 方言但是在整体上,C 语言保持着比其他语言更少的专有扩展最重要的擴展可能是意图处理某些 Intel 处理器的怪癖的‘far’和‘near’指针限定符(qualification)。尽管 C 语言最初设计不是以可移植性作为主要目标它成功于在范围从最尛的个人计算机到最强大的超级计算的机器上表述程序甚至操作系统。

C 语言是一个离奇的、有瑕疵的、和巨大的成功尽管历史上的事故嘚确应被避免,它明显的满足足够高效以替代汇编语言作为系统实现语言的需要而仍然足够抽象和流畅来在各式各样的广泛环境中描述算法和交互。

}

我要回帖

更多关于 p.cn app下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信