什么是C本地函数声明机制?

时间:2014-04-07 06:15:05

标签: c compiler-construction scope function-declaration

gcc中似乎允许使用本地函数声明,我发现了对此的讨论:Is there any use for local function declarations?

但是,我的问题是:ISO C标准是否允许?如果是的话,如何解释以下令人费解的现象:

int main(void) {
    int f(void);
    f();
}
void g(void) {
    /* g has no idea about f. It seems that the decl is limited within its
     * scope */
    f(); 
}
int f(void) {}

,而

int main(void) {
    int f(void);
    f();
}
void f(void); /* error because disagreement with the local declaration (local
             declaration goes beyound its scope?) */
void f(void) { /* definition here */ }

根据C99标准:函数名称在同一命名类别中。因此,我们将讨论范围机制来解释这一点。但是如何?

实际上,我正在开发一个编译器课程项目,该项目要求我们实现C编译器的简化版本。我试图处理这个案子,但感到困惑。

编辑:我知道C是面向过程的,并且要求函数名称是唯一的。但是这种地方性的宣言引起了清晰的局面,我很难理解其原则/规则。

3 个答案:

答案 0 :(得分:2)

ISO C和C ++都允许本地函数声明。在每种情况下,函数声明的范围都在本地范围的末尾结束。但是,函数声明及其定义具有外部链接,因此它们仍然需要被链接器接受。

在您的样本中:

int main(void) {
 int f(void);
 f();
}
void f(void);
void f(void) {  }

此代码无错误地编译为C或C ++。在C中应该链接(通常),但在C ++中它不会(因为“类型安全链接”)。 int f(void);将有一个未解决的外部。

[如果因为你的英语有困难而没有回答你的问题,请澄清,我会编辑答案。]


C标准包含以下内容。 n1570 / S6.7.1 / 7:

  

具有块作用域的函数的标识符声明不应该是明确的   除extern之外的存储类说明符。

显然,明确允许本地函数声明。


关于外部联系的n1570 S6.2.2 / 5:

  

如果函数的标识符声明没有存储类说明符,则其链接   确定与存储类说明符extern声明的完全相同。如果   对象标识符的声明具有文件范围,没有存储类说明符,   它的联系是外部的。

因此本地函数声明具有外部链接。这很明显:如果他们有内部联系或没有联系,他们就无法链接到任何东西。

答案 1 :(得分:0)

要修复第二个示例,您需要在main中使用正确的返回类型

声明f
int main(void) {
    void f(void);  // function declaration
    f(); // calling function
}  // scope of f ends here

void f(void) {} 

通过这种方式,您可以通知编译器要查找的内容,稍后它会确实找到它。希望它有所帮助。

答案 2 :(得分:0)

本地extern声明确实像函数之外的声明一样工作,除了范围有限,或者像本地static声明一样,除了实体可以通过链接从外部访问。

为什么呢?好吧,为什么不呢?它只是将声明的一般规则和extern说明符推断到特定的上下文中。

我无法(故意)回忆使用本地外部函数声明,但有几次我使用本地extern变量声明攻击了调试变量。 extern声明可以放在一些高度嵌套的代码中,并将数据传递给另一个TU中的调试打印机。