我们还需要子程序吗?
在 Fortran 中,函数和子例程之间存在明显的区别:函数返回一个值,子例程不返回任何值。这引入了两者之间的一系列差异。一个例子是调用语义:您可以像在其他语言中一样调用函数,但为了调用子例程,您必须首先发出 call
语句。
随着 Fortran95 中添加的指针和数据类型,使任何子程序成为函数以及保留子例程仅用于遗留似乎不再存在技术限制。函数可以返回零(您只返回一个虚拟整数)、一个或多个值(例如,您可以返回指向已分配类型实例的指针,如 C++ STL 对)。
我错了吗?由于子例程具有而函数没有的某些功能,我们在 Fortran 编程中是否仍然需要子例程?
In Fortran, a clear difference exists between function and subroutine: functions return one value, subroutines return no value. This introduce a cascade of differences between the two. One example is the calling semantics: you can call a function just as in other languages, but in order to call a subroutine you must issue a call
statement first.
With the addition of pointers and data types in Fortran95, it appears that there is no technical limitation in making any subprogram a function, and keeping subroutines just for legacy. Functions could return zero (you just return a dummy integer), one, or multiple values (for example, you could return a pointer to an allocated instance of a type, like a C++ STL Pair).
Am I wrong? Do we still need subroutines in Fortran programming due to some feature that subroutines have and functions don't?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您搜索 comp.lang.fortran 档案,您会找到有关函数语义的讨论。 IIRC 事实证明,标准中没有明确规定对于具有副作用的函数,什么是允许的,什么是不允许的。
例如,编译器可以将
x = foo(args) + foo(args)
优化为
x = 2 * foo(args)
或者再举个例子,考虑
x = y + foo(y)
如果 foo() 改变了值怎么办是吗?请记住,Fortran 没有 C 语言中的序列点概念。
一般来说,一些专家的建议是仅使用纯函数,否则使用子例程。而且,这也是我自己遵循的建议。
If you search the comp.lang.fortran archives, you'll find discussions about the semantics of functions. IIRC it turns out that it's not clearly specified in the standard what is and what isn't allowed for functions that have side-effects.
For instance, can the compiler optimize
x = foo(args) + foo(args)
into
x = 2 * foo(args)
Or for another example, consider
x = y + foo(y)
What if foo() changes the value of y? Remember that Fortran doesn't have the C concept of sequence points.
In general, the recommendation by several experts is to use functions only if they're pure, otherwise use subroutines. And, that is advice that I follow myself as well.
我不认为子例程会去任何地方。大多数其他语言都允许返回值和不返回值的方法。我看不出有什么理由认为这是一件坏事。任何人都不应该被感动去改变一件事。
仅遗产表明,子例程将像 Fortran 一样持续存在。只要 Fortran 存在,编写执行操作但不返回任何内容的方法就没有什么问题。
更新:
为什么说“麻烦”?有什么大不了的?我不同意子例程在适当的情况下使用时会带来“麻烦”的观点。
自版本 77 甚至更早版本以来,Fortran 一直保持函数和子例程之间的区别。其他 C 系列语言也是如此。怎么突然就这么麻烦了?即使是很长时间以来一直存在指针和对象的语言也有返回 void 的方法。
I don't think subroutines are going anywhere. Most other languages allow methods that do and do not return values. I can't see any reason why that's a bad thing. No one should be moved to change a thing.
Legacy alone says that subroutines will persist as long as Fortran does. And as long as Fortran is around, there'll be nothing wrong with writing a method that performs an action and returns nothing.
UPDATE:
Why do you say "hassle"? What's the big deal? I disagree with the idea that subroutines are a "hassle" when they're used in an appropriate situation.
Fortran has maintained a distinction between functions and subroutines since version 77 and probably earlier. Other C-family languages do, too. Why is this suddenly such a hassle? Even the languages that have had pointers and objects for a long time have methods that return void.
你又想用 fortran 来编写 C 程序了,不是吗? ;-)
在我看来,是的 - 我们确实如此。因为如果只有一个原因——它们比函数更容易掌握、理解,而且使用更广泛。
另外,-1,因为我认为这不是一个建设性的问题。如果您不喜欢它们,请不要使用它们。
You're trying to program C in fortran again, aren't you? ;-)
In my opinion, yes - we do. For if for one reason only - they're easier to grasp, to understand, and they're more widely used than functions.
Also, -1, for I believe this is not a constructive question. If you don't like them, then don't use them.
如果我理解正确的话,Stefano 并不反对子例程的想法。反对他们的意见是无稽之谈。他反对对子例程/函数使用不同的风格。
Fortran 是命令式编程语言。更准确地说,它是一种过程编程语言(更准确地说,它是结构化编程语言)。
在命令式编程中,我们有一个状态和改变它的语句。在过程编程中,我们进行更改的工具是过程(我们将更改本地化在过程中)。该过程可能会也可能不会返回某些值。我不认为这个事实(无论是否有过程返回值)是在编程语言中拥有两个不同实体的重要原因。当我们实际上不需要返回某些东西(void)时,我们可以只拥有函数(就像在 C 中一样)并且只返回一些特殊的东西。或者我们可以只使用允许返回值的过程和特殊语法,如 Modula-2、Oberon 等。
该语言可能应该只有一种声明过程的样式。我同意你的观点,斯特凡诺。
If I understand correctly Stefano is not against the idea of subroutines. The opinion against them is nonsense. He against the usage of different styles for subroutines/functions.
Fortran is imperative programming language. More precisely it is a procedural programming language (and even more precisely it is structured programming language).
In imperative programming we have a state and statements to change it. In procedural programming our tools to do changes are procedures (we localize changes inside procedures). The procedure may or may not return some value. And I don't think that this fact (either procedure return value or not) is so significant reason to have 2 different entities in the programming language. We can have only functions (like in C) and just return something special when we do not actually need to return something (void). Or we can have only procedures and special syntax permitting to return values like in Modula-2, Oberon, ...
The language probably should have only one style to declare procedures. I agree with You, Stefano.
事实上,我必须回答自己这个问题,这很疯狂,但事实就是如此。
差异源于这样一个事实:在 Fortran 中你不能“像其他语言一样调用函数”。在 C 中,您可以调用整数函数而不分配值,例如
在 Fortran 中,您始终必须关联接收变量。示例
意味着通过返回虚拟整数来“模拟” void 函数仍然不允许您在没有接收器变量的情况下进行调用。
在 Fortran 中,
void
返回类型不存在。从技术上讲,您可以使用所有函数构建您的程序,将每次出现的call
语句替换为x =
(如上所示),但这不会使您的语法类似于 C 或无论如何,其他语言中,void 返回函数和非 void 返回函数之间没有区别。子例程是唯一允许“返回 void”的实体,但执行调用的语义完全不同。除此之外,两者没有任何区别。The fact that I have to answer myself to this question is insane, but that's how it is.
The difference stems from the fact that you cannot "call functions like in other languages" in Fortran. While in C you can call an integer function without assigning the value, example
In Fortran, you always have to associate a receiving variable. Example
Meaning that to "emulate" a void function by returning a dummy integer would still not allow you to call without having a receiver variable.
In Fortran, the
void
return type does not exist. Technically, you could structure your program with all functions, replace every occurrence of thecall
statement withx =
like seen above, but that would not make your syntax similar to C or other languages anyway, where there is no distinction between void-returning functions and non-void returning functions. subroutines are the only entities that allow to "return void", but the semantic to perform the call is simply different. Apart from that, there's no difference between the two.