C中的子程序是否与Fortran中的子程序相似?

时间:2016-06-02 15:06:23

标签: c fortran

很长一段时间我一直在使用Fortran,最近我决定学习C.虽然我理解C中的函数是如何工作的,但我很难找到有关如何在C中实现与Fortran子程序等效的东西的信息。这个概念是否存在完全用C语言编写?

考虑一下这个Fortran代码:

module myMod
  implicit none
  contains

    function func(a, b)
      integer :: func
      integer, intent(IN) :: a, b
      func = a + b
    end function func

    subroutine sub(a, b, c)
      integer, intent(INOUT) :: a, b
      integer, intent(OUT) :: c
      a = a * b
      b = 3 * a
      c = a + b
    end subroutine sub

end module myMod

program example
  use myMod
  implicit none
  integer :: i, j, k

  i = 1
  j = 2

  k = func(i,j)
  print*, k

  call sub(i,j,k)
  print*, i, j, k

end program example

模块myMod中的函数将很容易转换为C,但子程序怎么样?有没有办法做类似的事情?

编辑:例如,下面的代码没有输出我的预期:

#include <stdio.h>

void subroutine(int num1, int num2) {
    num1 -= 1;
    num2 *= 2;
    printf("this has been executed! \n");
}

int main () {

    int a = 10;
    int b = 10;

    subroutine(a,b);
    printf( "a = %d, b = %d \n", a, b);

    return 0;
}

输出:

this has been executed!
a = 10, b = 10 

而不是预期的:

this has been executed!
a = 9, b = 20 

那么为什么在该void函数中修改变量a和b,就像Fortran子程序一样呢?

3 个答案:

答案 0 :(得分:5)

您可以定义一个函数,使其返回类型为void,这意味着它不会返回任何内容。

void返回类型的函数可能会使用return关键字而没有赋值,但不需要使用return

您可以按如下方式翻译上述子程序:

void sub(int *a, int *b, int *c)
{
    *a = (*a) * (*b);
    *b = 3 * (*a);
    *c = (*a) + (*b);
    printf("a=%d, b=%d, c=%d\n", *a, *b, *c);
}

并称之为:

sub(&i, &j, &k);

在C中,所有变量都按值传递,因此修改函数中的参数不会在调用者中反映出来。

由于您要修改传递给函数的值,而是使用&运算符传递要修改的每个变量的地址,并为每个变量指定一个一。然后使用一元*运算符取消引用指针来读取/写入它指向的值。

答案 1 :(得分:1)

函数不需要返回值 - FORTRAN子例程的替代方法是使用返回类型void声明函数。

void function(arguments){
...
}

这有效地使函数成为子例程 - 假设值通过引用传递给函数,那么函数可以更改超出其范围的变量。

在您的情况下,将函数声明为

void subroutine(int* num1, int* num2) { 
    /* num1 stores the address of a
     * and *num1 gives the value stored in that address
     */
    *num1 -= 1;
    *num2 *= 2;
    printf("this has been executed! \n");
}

并将其命名为:

subroutine(&a,&b); // &a means the address of a

答案 2 :(得分:1)

在某些情况下,您可以使用C预处理器来定义行为类似于子例程的宏。例如:

#define subroutine(X,Y) do{ \
  X -= 1; \
  Y *= 2; \
  printf("this has been executed!\n"); \
} while(0)

int main(int argc, char**argv)
{
  int a = 10;
  int b = 10;

  subroutine(a, b);
  printf("a = %d, b = %d\n", a,b);
}

结果:

this has been executed!
a = 9, b = 20

C宏是文字文本替换。外do...while(0)是一个非常标准的&#34;技巧&#34;用于创建一个多语句宏是可以调用的#34;就像一个函数一样,因为while(0)将吞下尾随;并被任何值得使用的编译器优化。尾随\行为准则允许您定义多行宏。

GCC(Gnu扩展,而不是标准C)的另一个广为人知的(很少使用的)功能可能会让你在某些情况下产生影响,那就是你可以在函数内部定义一个函数,然后内部函数可以访问外部函数的本地范围变量。

Gnu C Reference manual sections on nested functions

例如:

#include <stdio.h>

int main(int argc, char**argv)
{
  int a = 10;
  int b = 10;

  void subroutine(){
    a -= 1;
    b *= 2;
    printf("this has been executed!\n");
  }

  subroutine();
  printf("a = %d, b = %d\n", a,b);
  subroutine();
  printf("a = %d, b = %d\n", a,b);
  subroutine();
  printf("a = %d, b = %d\n", a,b);
}

导致输出结果:

this has been executed!
a = 9, b = 20
this has been executed!
a = 8, b = 40
this has been executed!
a = 7, b = 80

这两种技术都存在很多陷阱,并且通常不属于“最佳实践”的范畴。在C中,但是任何一个都可以成为一个强大的工具,试图逐渐将代码(和你的想法)从fortran迁移到C.