在另一个函数中定义函数的范围

时间:2014-11-19 10:39:09

标签: c function gcc user-defined-functions

在另一个函数中定义函数时会发生什么?代码1和代码2之间有什么区别?

代码1:

#include<stdio.h>

void m();

void main()
{
    m();
    void m()
    {
        printf("hi");
    }
}

代码2:

#include <stdio.h>

void m();

void main()
{
    void m()
    {
        printf("hi");
    }
     m();
}

当我在gcc编译器中编译代码1 时,我遇到了链接错误。但是当我编译代码2 时,我没有收到任何错误。我输出“hi”。当我们在另一个函数中编写函数定义时,我想知道编译是如何完成的。我知道当我们编写函数定义不在另一个函数中时,无论函数定义在哪里,我们调用该函数时都不会出现任何错误。 例如,请参阅以下代码:


代码3:

#include <stdio.h>
void m();
void main()
{
    m();
}

void m()
{
    printf("hi");
} 

代码3 中,即使我在定义之前调用了该函数,它也没有显示任何错误,我得到了输出。为什么代码1 没有发生。

6 个答案:

答案 0 :(得分:2)

您无法在函数内定义函数。 C中不允许这样做,因而无法编译。代码段1和2无效,只有代码段3是有效的ANSI C代码。

为什么代码1无法编译,代码2在gcc中编译良好
由于GNU compiler extension,代码2在gcc下编译。您必须在首次使用之前声明该功能才能使此扩展工作。

那么为什么代码3会编译
在Snippet 3中,您在第一次使用之前声明该函数,这足以让编译器放置所需的代码。在链接时,需要与定义代码进行必要的链接。链接器没有必要放置定义(在ISO C规范中),即使在单独的编译单元中也允许函数定义出现。

答案 1 :(得分:2)

C和C ++都不允许在另一个函数中定义函数。因此,您似乎正在使用编译器GCC的特殊语言扩展,它允许在另一个函数内定义本地函数。

在第一个程序中,函数m在文件范围内声明。因此,编译器将在文件范围内搜索其定义。在main内部调用该函数时,此文件范围声明是可见的。但是,编译器未找到其文件范围定义,因此它发出错误。

在第二个程序中,文件范围中还有一个函数m的声明。但是在函数main内部还有另一个函数m的声明,它具有块作用域并用文件作用域隐藏声明。考虑到定义也是一个声明。所以m的调用指的是在main中声明的函数m并且具有块作用域。编译器具有函数定义,可以调用它。

在满足C标准的第三个程序中,m的调用是指在文件范围内声明的函数m,并且在文件范围内有该函数的定义。所以没有任何问题。

答案 2 :(得分:1)

这是一个范围问题。在您的CODE 1示例中,m函数仅在main函数中可见。所以你放在main之前的函数头(void m();)期望一个全局的m函数并且没有找到它,这就是你有链接错误的原因。在你的代码2样本中,找到了m函数,因为它是在调用之前写的,你的全局m函数仍然不存在但未使用=&gt;你没有链接错误。在您的代码3示例中,您的m函数是全局的,然后通过header =&gt;按预期找到没有错误

答案 3 :(得分:1)

  

在代码3中,即使我在定义之前调用了函数,它也没有显示任何错误,我得到了输出。为什么代码1没有发生?

代码3符合标准C代码。只要声明可见,就可以调用具有外部链接的函数(如果程序中某处存在定义,则它不必位于同一文件中)。

  

当我在gcc编译器中编译代码1时,我遇到了链接错误。

嵌套函数是GCC extension

  

嵌套函数始终没有链接。用extern或static声明一个是错误的。如果需要在定义之前声明嵌套函数,请使用auto(这对函数声明来说没有意义)。

在调用m点时,可以看到外部声明(文件范围声明void m();)。由于此源文件中没有外部定义,gcc假定它位于另一个转换单元中,并且最终链接器无法找到它。根据引用的文档,有效版本可能是

#include <stdio.h>

int main(void)
{
    auto void m(); /* Hides the outer declaration. */
    m(); /* Refers to the nested function, not to an external one now. */
    void m()
    {
        printf("hi");
    }
}
  

但是当我编译代码2时,我没有收到任何错误。输出“hi”。

在调用m的位置,嵌套函数可见,隐藏文件范围声明。从不使用文件范围声明(声明具有外部链接的函数),因此链接器不会尝试解析对它的调用。


符合要求的实现可以接受main作为返回void的函数的声明,但不必。旧式(或K&amp; R式)声明和定义在C89,C99和C11中已过时,因此最好使用

int main(void);
void m(void);

答案 4 :(得分:0)

检查以下链接: Nested function in C

C不支持嵌套函数,因此您的代码片段1和2不允许使用标准,尽管您可能会看到代码片段2正常工作,因为您在函数定义后有函数调用。

唯一允许的代码段是Code 3,其余部分不应在C中完成。

GCC特别扩展: https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

答案 5 :(得分:-1)

您没有将您的代码编译为标准C. GCC非常棘手,因为默认情况下它会带有糟糕的非标准设置。要将GCC用作正确的C编译器,必须执行gcc -std=c11 -pedantic-errors,其中c11是首选标准(如果您有旧版本的GCC,请切换到c99)。在此期间,请确保同时启用所有警告:

gcc -std=c99 -pedantic-errors -Wall -Wextra

既然编译器已配置为C编译器,我们会收到以下错误:

CODE1和CODE2:

  •   

    错误:返回类型&#39; main&#39;不是&#39; int&#39; [-Wmain]。

    出现此错误是因为当GCC设置为C编译器时,它不提供实现定义的方法来指定main。您必须将main更改为int main (void)

  •   

    错误:ISO C禁止嵌套函数[-Wpedantic]

    出现此错误是因为C标准不允许嵌套函数。你之前已经离开了它,因为你已经将GCC设置为非标准编译器。