函数原型在c文件而不是标头中的范围

时间:2018-11-21 05:31:23

标签: c scope

很抱歉是否曾问过这个问题(我只在SO上找到了该问题的变体,但没有找到确切的变体)

我的问题是关于范围w.r.t,其中定义了函数原型。

假设我们有3个文件:test.htest.cmain.c

main.ctest.c都包含test.h

test.c

int f2(int b); // function prototype (local)

int x=0;
// public function
int f1(int a){
 return a*5;      
}
// local function
int f2(int b){
 return b*10;
}

test.h

int f1(int a);

main.c

#include "test.h"
int x=1;
int main(){
    printf("%d \n", f1(5));
    printf("%d \n", f2(5));
    return 0;
}

我的问题是:

  • main.c是否可以访问f2()并在test.c内部声明原型并进行访问
  • main.c可以访问f1()吗?还是需要将其声明为extern
  • main.c是否可以访问x内部的test.c全局变量?它会与x中定义的全局变量main.c(同名)冲突吗?
  • 要获得本地范围,是否必须使用static关键字?
  • 静态函数可以访问在同一.c文件中定义的全局变量(静态/非静态)吗?

3 个答案:

答案 0 :(得分:3)

在回答您的问题时,我想将两个.c源代码编译并链接到一个程序中。

  
      
  • main.c是否可以访问f2()并在test2.c内部声明原型并进行访问
  •   

现代C不允许调用在范围内没有声明的函数,但是K&R C允许此类调用,并且大多数实现仍然允许它们。而且,main.c可以声明函数本身,然后调用它。

  
      
  • main.c可以访问f1()吗?还是需要将其声明为extern
  •   

默认情况下,函数具有外部链接。因此,extern是函数声明的默认值。您可以明确指定extern,但这很多余。

  
      
  • main.c是否可以访问x内部的test.c全局变量?它是否会与在中定义的全局变量x(相同名称)冲突   main.c?
  •   

是,不是。一个程序包含具有外部链接的相同标识符的两个定义是错误,并且您的x声明确实确实构成了定义,并且两者(默认情况下)确实具有外部定义。链接。

但是,有些实现会将它们合并为一个变量,另一些则拒绝链接程序,而另一些甚至可能维护单独的x变量。

顺便说一句,声明在源文件之间共享的变量的正确方法是对每个文件声明extern,而对它进行初始化。通常,没有初始化程序的extern声明将进入头文件,而带有初始化程序的单个声明(使之成为定义)将进入一个.c文件。示例:


test.h

extern int x; // _with_ extern, _without_ initializer

test.c

#include "test.h"
int x = 0;  // 'extern' is optional here

main.c

#include "test.h"
// no further declaration of x here

  
      
  • 要获得本地范围,是否必须使用static关键字?
  •   

staticextern关键字与链接有关,而不是范围。链接与哪些代码可以访问哪些对象和功能有关。范围是关于哪些代码可以看到哪些声明。尽管它们听起来很相似,但是实际上它们是截然不同的概念,因为可以多次声明同一对象或函数。实际上,这是例行程序,它是头文件提供的主要目的之一。

  
      
  • 静态函数可以访问在同一.c文件中定义的全局变量(静态/非静态)吗?
  •   

是的,我将“全局”解释为“在文件范围内声明”。 C没有全局变量本身的概念,但是在任何函数外部声明的对象在程序的整个过程中都存在。具有外部链接的代码可以从程序中其标识符声明在范围内的任何代码访问。那些具有内部链接(用static关键字声明的链接)只能从同一翻译单元(大致表示同一.c文件)中进行访问。

对象也可能具有 no 链接。在函数内部声明的对象就是这种情况。

答案 1 :(得分:1)

1)是,但偶然。没有声明符的函数将默认为int类型,其参数将默认为int类型,存储类将默认为extern。您的函数恰好已经具有这些类型。因此,严格来说,不需要声明器(尽管不使用声明器是非常糟糕的做法)。但是,在C99中,这显然已被视为非法,并且,如果您使用的是C99语义,则应该得到一个错误;否则,可能会出错。否则只是警告(-Wimplicit-function-declaration)。

2)如上所述,test.h声明符中缺少存储类说明符将隐式声明f1为extern。一切都很好。

3)链接器将引发有关重复标识符的错误。如果您使用extern int x;(不进行初始化),则可以使用。变量不获取隐式声明;如果您仅尝试在x中使用main.c而没有上面的声明,则会出现关于使用未声明变量的错误。

4)static表示几种不同的含义。我认为问题在于静态函数。这仅将功能的可见性限制在当前编译单元中。没有其他效果。

5)如上所述,将函数设为静态只会影响可以访问 it 的内容,而不会影响 it 可以访问的内容。

答案 2 :(得分:0)

  

main.c是否可以访问已实现的f2()并在test2.c中声明原型?

函数f2将被用作默认函数,该函数的返回值是int,参数为int。但是,如果您使用不同的参数,则会出现错误。

从C99开始,默认功能不适用,这将导致错误。

  

main.c可以访问f1()吗?还是需要将其声明为extern

是的,当您包含test.h时,它可以访问f1()。但是,您还需要编译test.c并将这两个文件都提供给链接器。

f1()中的

test.h声明不需要声明为extern。默认情况下,函数声明为extern。

  

main.c是否可以访问test.c内部的x全局变量?它会与main.c中定义的全局变量x(相同名称)冲突吗?

您需要将变量链接在一起。完成后,您将为此获得链接器错误。

  

要获得本地范围,是否必须使用静态关键字?

如果变量在函数外部声明,则为全局变量。要使其成为本地作用域,您需要专门使用static关键字。

  

静态函数可以访问在同一.c文件中定义的全局变量(静态/非静态)吗?