副标题#e#
本文具体先容C语言和Fortran语言的差别
1. C++语言和Fortran语言的成长配景
在措施设计语言的成长进程中,FORTRAN 语言被认为是科学计较的专用语言。厥后推出的FORTRAN90 和FORTRAN 95 版本也不破例,它们固然可以完全实现C++语言同样的成果,然而其软件开拓情况和软件的集成性等方面都远不如C++ 语言。连年来,跟着计较机软硬件技能的成长,数据布局、数据库打点技能、可视化与计较机图形学、用户接口系统集成以及人工智能等规模的成就被逐渐应用到布局阐明软件中,布局阐明软件的设计并不只仅范围于单一的科学计较需要涉及浩瀚的软件开拓规模。C++ 语言可以提供这类软件开拓所需的成果,而用FORTRAN 90 却很难实现,另一方面从软件的编程情况来看,今朝FORTRAN 90 的编译器少少,而C++ 语言的编译系统相当普及,可以运行在各类机型上,便于实现跨平台的软件系统集成。
2. C语言和Fortran语言的差别
由于两者发生的配景差异,它们是存在差此外,在较量了几组源代码之后,主要有以下体会:
C 最大的利益在于机动,不单可以藉由 struct 来界说新的数据布局 ,同时 C 的pointer 更可以让我们自由并且有效率地处理惩罚大数据。而在 UNIX 系统 中,由于整个操纵系统绝大部门就是 C 写出来的,故我们也有利便的 C 函数库, 直接利用系统资源与享受系统带来的处事,以做到一些低阶、快速的行动。而FORTRAN从一开始就用于科学计较,它与C的差别主要表示为:
* 复数运算的速度
* 措施参数与字串
* 内存的动态打点
* 多维阵列的处理惩罚
* 函数挪用与参数通报
2.1. 复数运算的速度
在举办复数运算的时候,C++ 可以界说复数的 class,还可以从头界说所有的四则运算式,巨大的算式也可以做到由一个表达式来办理。但它的从头界说复数四则运算是用函数来做的,利用函数来挪用其速度很慢,除非回收 inline function 的方法,但会碰着以下的问题:要先将这个算式拆解,别离算事后再重组功效,故外貌上措施代码很简捷,但实际上是 compiler做了许多事情,照旧要支付相当的计较时间价钱的。
至于 Fortran,最大的利益在于复数 (complex number) 的运算,复数是 Fortran 的根基数据范例之一,这正是 C 所缺乏的 (C 根基上只有实型与整型范例罢了)。 固然C 也可以由 struct 的界说,到达复数四则运算的目标,但 却很大概牺牲了措施效能,可能是措施写起来相当繁杂低落可读性。因此,在大量并且要求高速的复数运算场所, Fortran 实际上比 C 还要适合。
然而既然复数已是 Fortran 根基数据范例之一,则 Fortran compiler在设计上可以做到对复数出格的 optimization,譬喻假如碰着较短的复数运算式,它可以用“心算” 直接得出 real_part 与 imag_part 的 expression,像这样:
real(a) =……;imag(a) = …….
如此只需两步就获得功效。直到碰着太长太巨大的算式,才去做拆解的行动。
这样利用 C 来做复数运算大概需要绕圈圈,并且绕出来的圈圈大概还不小。不外假如措施中需要复合的数据布局,如一个自界说的数据布局中既有浮点数、整数、尚有字符串时, Fortran 只有举白旗投降了。虽然, Fortran 假如要做照旧可以做,只是不太利便,并且大概也需要绕圈圈。但假如利用 Fortran 90 则不成问题了,因为 Fortran 90 也有雷同 C 的 struct 布局以界说复合的数据范例。
2.2. 措施参数与字串
C 措施可以有参数串列, Fortran 则没有。譬喻,当措施执 行时,必需输入 a, b, c
三个参数,在 C 可以这样写:
int main(int argc, char **argv)
{
int a, b, c;
a = atoi(argv[1]);
b = atoi(argv[2]);
c = atoi(argv[3]);
}
而措施执行时,参数就是这样传入: a.out 12 15 18
#p#副标题#e#
Fortran 却没有步伐 ,要传入任何参数,只能透过对话的方法:
integer a, b, c
c ------------------------------------
write(*,*) ''please input integer a:''
read(*,*) a
write(*,*) ''please input integer b:''
read(*,*) b
write(*,*) ''please input integer c:''
read(*,*) c
c ------------------------------------
end
2.3. 内存的动态打点
C 可以动态分派存储空间给任何数据范例,而Fortran 却不可。
譬喻:
float *c_function(int cnt)
{
float *a;
a = malloc(sizeof(float) * cnt);
/*
* 操纵 array a.
*/
return a;
}
并且假如在措施执行进程中,假如不再需要这个 array a 了,还可以随时释放a所占用的存储空间。而 Fortran 在一般环境下是不可的,因此在一般的 Fortran 措施中,常见所有需要用的 array, 都是在 MAIN__里头就设置好记存储空间,再一个个传入subroutine 里头来用,譬喻:
program fout
c ----------------------------
integer cnt
parameter (cnt^P00)
real a(cnt)
call f_routine(cnt, a)
end
c ----------------------------
subroutine f_routine(cnt, a)
c ----------------------------
integer cnt
real a(cnt)
c
c 操纵 array a.
c
end
#p#分页标题#e#
这里的 parameter 是设定变数的牢靠值,其浸染就相当于 C 的 const 一样,经设定后的参数就是一个无法改变其值的常数了。有的时候,在某个函数中我们姑且需要一个暂存阵列,但比及计较完成分开函数后,该阵列就没有用了,这在 C 可以做的很划算,即进入函数时malloc() 一个阵列,分开前再 free() 掉它。但在 Fortran 中却别无选择,必然要在 MAIN__ 里头先将暂存阵列设置好,再一起传入 subroutine 中。
2.4. 多维阵列的处理惩罚
岂论是在 C 或 Fortran, 所谓的多维阵列实际上只是一个很长的一维持续存储空间,颠末支解后当做多维阵列利用。譬喻,一个 C 的二维阵列声明如下:
double a[12][10];
则它在存储空间中的设置为:
|<— 10 —><— 10 —> …. <— 10 —>|
|<<————– 共 12 组 —————>>|
所以它实际上是一块 12*10*sizeof(double) bytes 的持续存储区块,而经过以上的声明,compiler 便知道当利用到它时,要将支解成每单元元素为 sizeof(double),每 10 个单元一组,而总共 12 组的一个二维阵列,则当我们利用阵列的 index 来存取阵列元素时, compiler 也会自动算好该元素阵列在此存储区块的位置,因此就能很利便地利用。
Fortran 也是如此,但有一个很大的差异,它的存储区块支解设置的方法是与 C 反向的。譬喻声明一个二维阵列如下:
double precision a(12,10)
则它在存储空间中的设置为:
|<— 12 —><— 12 —> …. <— 12 —>|
|<<————— 共 10 组 ————–>>|
因此,假如我们要在 Fortran 中设置一个与上头谁人 C 一模一样的二维阵列时,实际上应该要将其 index 反过来:double precision a(10,12)
除此之外, C 的阵列 index 一律是从 0 开始,对付一个有 N 个元素的阵列,其最后一个 index 是 N-1,且每个阵列元素的 index 值差 1。 Fortran 不必然,要看怎么声明白。譬喻声明一个阵列如下:
double precision a(100)
则此阵列 index 是从 1 开始,最后一个是 100, 每个的值差 1。不只如此, Fortran 还可以这样声明:
double precision a(11:110)
这照旧一个一维阵列,共 100 个元素,但第一个元素的 index 是 11, 最后一个是110 。在这里我们可以看到, (idx1:idx2) 这样的论述在 Fortran 中就是用来指定一个阵列的范畴。
2.5. 函数挪用与参数通报
C 的函数挪用就只有一种方法,函数可以传入参数,也可以返回值,譬喻:
void c_function1(int a, float *b)
{
........
}
int c_function2(int a, float *b)
{
int r;
........
return r;
}
int main(void)
{
int a, r;
float b;
c_function1(a, &b);
r = c_function2(a, &b);
}
个中 c_function1() 没有返回值,而 c_function2() 有返回值。而 C 函数的参数传入则有两种方法,正如前面的例子,一个是 call-by-value, 即 (int a),另一个是call-by-reference, 即 (float *b),二者的不同在于:call-by-value 是将参数值复制一份副本到子函数的参数列中,让子函数利用,就算子函数改变了副本的值,也只是改变了子函数中的副本,也不会影响到上层父函数的原参数值。Call-by-refernce 则相反,它则是将参数地址的地点当做参数传给子函数中,子函数只知道此参数的存储空间地址的地点,它要存取该参数时,必需由此地点去找到该参数。因此,子函数利用的,其实是与父函数沟通的一个参数,故假如子函数改变了此参数的值,则父函数的参数值也随着改变了。
而Fortran又与 C 相反了。它的函数有两种,一为 subroutine,一为 function。subroutine不会有传回值,但 function 有传回值,就以上 C 的例子, Fortran 的写法如下:
subroutine f_function1(a, b)
integer a
real b
........
end
integer function f_function2(a, b)
integer a
real b
........
f_function2 = ....
end
program fout
integer a, r, f_function2
real b
c -----------------------------------
call f_function(a, b)
r = f_function2(a, b)
end
#p#分页标题#e#
若从 C 的概念来看, subroutine 其实就相当于 C 的无返回值函数,而 function 就相当于 C 的有返回值函数。但 Fortran 的 function 还要更非凡一点,可以看到,当措施要利用 f_function2 时,必需先申明:
integer f_function2
因为它的返回值是 integer。这有点像Fortran 将 function 看做是参数的一种,只是这个参数不太简朴,它背后还带着陆续串的计较。再看看 f_function2 实际上的写法,在 C 的有返回值函数中,最后必然要用 return 将要返回的参数返回i来,但Fortran 则不是,它是必然要将返回的值设成该函数名(即 f_functio n2), 如此即可返回。这就仿佛是, function 自己就是一个参数。
岂论是 Fortran 的 subroutine 或 function 的参数,其传入的方法就只有一种,就是 call-by-reference,所以在上述所有的 Fortran subroutine/function 的参数中,假如子函数改变了参数值,其父函数的相对应参数也会随着改变。
最后说一点,Fortran 不像 C,所有用到的参数到要声明,就算不声明也可以直接用。 若不声明时,那些参数是有预设型此外,就视其参数名而定,譬喻参数名以 i, j, k, l, m, n 字母为首者,其预设型别即为 integer, 不然为 float。