新的C语言:一切都源于FORTRAN

2024-04-07 17:32
文章标签 语言 源于 fortran

本文主要是介绍新的C语言:一切都源于FORTRAN,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

新的C语言:一切都源于FORTRAN

此篇文章摘取于即将登载于《Dr.Dobb's 软件研发》第三期(2003年10月)的《The New C:一切源于FORTRAN》,文章主要是介绍了C99的新特性受限指针,在得到作者Randy Meyers以及《Dr.Dobb's 软件研发》杂志负责人刘江先生的应允下,把全文的前面的一部分作为文档发表,希望能对大家有所帮助。

 

 

新的C语言:一切都源于FORTRAN

译注:本文是作者Randy Meyers在 CUJ杂志开的一个专题系列The New C的第二篇文章,主要是叙说C99中的新关键字restrict以及受限指针(restricted pointers)的历史渊源和使用方式。受限指针作为一种编译器优化代码的方式,是由编译器厂商提供特定的实现,因此这篇文章所谈论的并非在一切实现中都能得到支持,至于如何使用restrict关键字,这篇文章做了很好的说明,期望本文能给关心C语言和使用C语言的用户带来帮助。在翻译上,所有译者在翻译过程中有疑惑的术语或者其他一切都以括号形式把原文直接给出,诚心不想给读者半点误导,但是否如愿还需读者的评判,关于本文的一切可以用amstrongest@hotmail.com与译者联系和讨论。

 

有时候改进一种语言的最好方式就是让它和三十年前的古老样子更相似

 

 

 

一切都源于FORTRANIt all began with FORTRAN)。

 

谈起上面的话,我并不是想说FORTRAN是第一个程序设计语言,但是在上个世纪六十年代(1960s)的一场关于如何在FORTRAN中实现参数传递的争论,却意外的使FORTRAN在七十年代(1970s)的超级计算机上面的性能有了巨大的提升,并且导致了九十年代(1990s)一个关于C语言的新特征被C99所接受,这就是受限指针(restricted pointers)。而理解受限指针的原始动机的最好方式就是回顾历史,重温发生在FORTRAN中的那个由争论所导致的意外。

 

C不一样的是,在FORTRAN中如果一个函数被分配了一个新值作为参数,传递给函数的实参值将会改变,并且在函数返回时,调用者将会得到新的参数值。考虑下面Example 1所例举的代码,如果你以Y作为参数调用F,在F返回时,Y值将会是6[译注:下面的程序没有出现变量Y,文中意思是Y是实参数,而下面程序出现的X是形参数,只是属于函数F的内部变量,但是当把Y复制给X后,并且改变X同时将改变外面调用的Y的值]

Example 1:

SUBROUTINE F(X)
INTEGER X
X = 6
END

这样的参数传递方式就使争论随之而来。不同的FORTRAN编译器可以选择两种实现方式中的一种来获得FORTRAN中的参数传递语义。第一种方式是引用参数传递(by reference),也就是典型的C程序员所使用的:写一个函数,并且在它的调用者中修改变量。(write a function that modifies a variable in its caller)。传递给函数的是一个参数的地址,并且在需要的时候任何地方都可以间接访问这个参数。如果FORTRAN编译器产生C代码的话,就会和下面Example 2.C代码类似。

Example 2:

void f(int *x)
   {
   *x = 6;
   }

然而,对于一些类型的计算机来说,间接访问局部变量比直接引用访问所带来的运行时开销要大的多。这也就导致了FORTRAN中参数传递的第二种实现方式。实参的地址依然会被传递给函数,但是函数一旦被调用,就将生成一个实参数的局部拷贝[译注:传递的是地址,但是函数内部拷贝的却是参数值],在函数生存期中将一直使用这个拷贝的局部变量,当函数返回时,将把拷贝变量赋值给调用函数的参数变量。这样的FORTRAN编译器如果产生C代码将会和下面的Example 3相类似。进/出拷贝(copy in/copy out)参数传递方式增加了函数进入和返回时的负担,但是如果一个参数被多次引用,而间接引用(在一些机器上代价十分昂贵)却不再使用的话,导致的结果就是性能的提升(在一些机器上面而言)。[译注:就是说第一种方式的主要的调用开销是间接引用,第二种方式的主要调用开销是拷贝变量,其中哪种更好,需要根据真实代码的情况衡量决定]

Example 3:

void f(int *x)
   {
   int xcopy = *x;
   xcopy = 6;
   *x = xcopy;
   }

大多数时候,编译器如何实现语言特征通常都被认为不过只是“实现细节”。它们不会影响程序员编写程序的方式,而语言的标准委员会允许语言的实现者自由选择和改变实现方式。然而,根据使用的参数传递机制,FORTRAN程序会产生不同的结果。考虑下面Example 4中的FORTRAN代码,以及以两种方式转换成的C代码:

Example 4:

SUBROUTINE G(X, Y)
INTEGER X, Y
X = 1 + X
Y = 5 + Y
END
 
// Translation using "by reference"
void g(int *x, int *y)
{
   *x = 1 + *x;
   *y = 5 + *y;
}
 
// Translation using
// "copy in/copy out"
void g(int *x, int *y)
{
   int xcopy = *x;
   int ycopy = *y;
   xcopy = 1 + xcopy;
   ycopy = 5 + ycopy;
   *x = xcopy;
   *y = ycopy;
}

G函数给它的参数加上了不同的常量,如果你把参数AB传递给函数G,并且在调用前A的值是1B的值是10。不用怀疑,无论使用FORTRAN中的那种函数参数传递机制,当函数返回时A的值将变成2B的值将变成15。但是请考虑,如果你传递参数都是的A(并且被初始化为1),将会是什么情况?如果是使用引用调用(by reference)的参数传递机制,在函数返回时A将的值将变成7A的值在赋值给*x的过程中时候被更新,因为xy都指向A,所以在随后的对*y赋值的过程中A的值将再次被改写。相反,如果是使用进/出拷贝(copy in/copy out)的参数传递机制,在函数返回时,A的值将是6。调用发生后,在函数G中将不同的拷贝变量,并且每一个都将在函数返回时赋值给A,但最后的一个拷贝变量的返回值才会成为A的终值。

 

这两种不同的参数传递机制是任何程序设计语言定义者所必须面对的不一致性的代表。语言需要特殊的实现实现技术吗?也许这将会以付出效率为代价?语言的特性是否应该为了避免争议而改变?FORTRAN的定义者因为效率而允许同时存在两种参数传递机制。而一旦这样的决定做了出来,某种类型的程序就变的不一致了,并将导致无法定义的结果(outlawed)。

 

FORTRAN 66 标准包含了一系列可能会误导程序员的规则。在函数参数列表中,对于任何变量你都只能传递一次。如果你传递了一个变量作为函数参数,那么这个函数就不能再在全局上引用这个变量(FORTRAN COMMON)。如果你传递给一个变量给函数,你就不能再传递任何东西,并且这个函数也不能再引用任何东西,that overlaps it in storage (FORTRAN EQUIVALENCE)。在这样的规则下,没有什么程序可以确定应该采用何种参数传递机制。

 

大约十年以后[译注:意指1970s],为了实现超级计算机Cray 1的高性能,超级计算机需要高优化的编译器来使传统的程序能够使用机器的向量寄存器(vector registers)。考虑Example 5中的程序。其中对于函数来说最有效率的代码就是先后把数组指针xy载入到向量寄存器中然后执行向量加指令来把两个向量寄存器中的变量加在一起。如果编译器以产生向量指令的方式来取代传统的使用循环来访问数组中的每一个元素的方式,那么代码的运行效率将得到巨大的提升。

Example 5:

void
vector_add(float *x, float *y,
   float *result)
   {
   int i;
   for (i = 0; i < 64; ++i)
      result[i] = x[i] + y[i];
   }

编译器中的优化器肯定会把循环转化成一系列的向量指令,但是问题在于那些向量指令是否真的whether the sequence of vector instructions is really equivalent to the original loop。你能在处理result数组的存储工作之前就把x,y数组载入到向量寄存器中,只因为你清楚result数组和x,y数组都是不同的个体。考虑如果result指向x[1],将会发生什么?在这种情况下result[0]其实就是x[1],同样result[I]其实就是x[I+1],每一次循环迭代过程中都会存储下一次的迭代中会被引用的变量。如果在做result的存储工作之前就把x载入到向量寄存器中去,变量值将会改变calculated change。正是在这一点上,FORTRAN的定义就带来了冲突。为了避免在传递机制中需要引入一个特殊的参数,FORTRAN标准定义了一系列精确的规则用来允许向量化编译器(vectorizing compiler)假设x,yresult都是互不相关的,non-overlapping arrays。就这样偶然的,FORTRAN在向量机上就有了巨大的性能优势。

这篇关于新的C语言:一切都源于FORTRAN的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883226

相关文章

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

C 语言的基本数据类型

C 语言的基本数据类型 注:本文面向 C 语言初学者,如果你是熟手,那就不用看了。 有人问我,char、short、int、long、float、double 等这些关键字到底是什么意思,如果说他们是数据类型的话,那么为啥有这么多数据类型呢? 如果写了一句: int a; 那么执行的时候在内存中会有什么变化呢? 橡皮泥大家都玩过吧,一般你买橡皮泥的时候,店家会赠送一些模板。 上