函数声明

函数声明说明了一个原型,但没有指定函数体。放置了一个分号,而不是一个有主体的代码块。

声明对于编译器来说是必要的,这样编译器才能在后续代码片段中检查函数调用是否正确(包括按名称调用、向它传递自变量和获得结果)。

整个函数定义(包括函数体)也是一个声明,所以除了定义之外不需要声明函数。

例如,上述 Fibo 函数的声明是这样的。

int Fibo(const int n);

从几个带有源文本的文件构建程序时,将使用单独的函数声明和定义:然后在扩展名为 mqh 的头文件中进行声明(参见 #include 预处理程序指令一节),这个头文件包含在使用该函数的文件中,函数定义仅在其中一个文件中实现。函数签名在声明和定义中的匹配提供了防错功能。也就是说,单个声明保证了对整个源代码所做更改的一致性。

如果我们声明一个函数并在代码的某处调用该函数,但没有为其提供完全合适的定义,编译器将抛出一个错误:“函数‘名称’必须有一个主体”。这种情况经常发生,比如因为声明或定义中有拼写错误或不准确,以及在更改源代码的过程中,一些更正已经完成,而另一些很可能被遗忘。

如果函数被声明但没有在任何地方使用,编译器也不需要这个函数的定义 - 这个元素就从二进制程序中“切掉”了。

声明/定义语句 一节中,我们分析了 Init 函数的一个例子(StmtDeclaration.mq5 脚本),该函数用于初始化变量。其中特别说明了一个问题,全局变量 k 不能在 Init 函数之前定义,因为初始值 k 是通过调用 Init 获得的。编译器会抛出错误“'Init' 是未知标识符”。

现在我们知道,这样的问题可以通过一个声明来解决。在 FuncDeclaration.mq5 脚本中,我们在 k 变量之前添加了以下 Init 函数的前向声明,并将 Init 定义留在 k 之后。

// preliminary declaration
int Init(const int v);
// before adding preliminary declaration above
// here was an error: 'Init' is an unknown identifier
int k = Init(-1);
int Init(const int v)
{
   Print("Init: "v);
   return v;
}

现在脚本可以正常编译了。从技术上讲,在这种情况下,我们只需将函数移到变量上方,而不需要预先声明。这样做是为了解释这个概念。然而,在某些语言元素相互依赖的情况(如类)下,即使是在同一文件中也必须使用前置声明。