C - extern,static,include

时间:2015-03-10 15:46:35

标签: c static extern scoping

在C中确定范围是令人困惑的。我有一个变量:“int qwe”。这个var应该在一个或多个文件中可见 - 在这种情况下是f1.c,而不是另一个f2.c。

说我有:main.c,f1.c,f2.c,header.h

主: call f1(); 叫f2();

头:

#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED

int qwe = 1;
void f1();
void f2();
#endif // HEADER_INCLUDED

在f1.c:

#include <stdio.h>

extern int qwe;

void f1(){
    printf("In f1: %d\n", qwe);
}

f2.c:

#include <stdio.h>

static int qwe = 2;

void f2(){
    printf("In f2: %d\n", qwe);
}

现在这让人感到困惑。有定义和声明。我在标题中定义了qwe,在f1.c中声明了它。那是对的吗?应该在f1.c中的头文件和声明中进行定义吗?我尝试了后一种情况,但得到了一个错误 - “qwe的多重定义”。当我从f1.c中删除#include指令时,它工作...当我删除extern关键字时它也有效。外部多余?

f2.c我猜它没问题,表现如预期,或者是这样吗?但是,如果我将#include与标题放在一起,它会中断。那是为什么?

我什么时候应该在源文件中使用#include?如果我不包括它f1.c或f2.c它的工作原理......

另外,如果我在函数内部将变量定义为静态,如static int i = 0;当函数存在时,该变量不会被销毁,它将保留它的内存和数据。下次调用相同的函数时,可以访问它,对吧?但var不会重新初始化为0,即定义的行将不会执行。正确的吗?

生活踩到我:(

5 个答案:

答案 0 :(得分:2)

在标题中,声明变量。在例如f1.c中,定义变量,例如int qwe = 1; //在全球范围内。

在所有想要查看/更改qwe的文件中,包含声明变量的标头。易于peasy。

答案 1 :(得分:2)

您需要在标题中声明变量,并在一个且仅C个文件中定义

在C中,您不能拥有不属于给定翻译单元(源文件)的变量。所以它必须由整个程序中的一个翻译单元定义。

当您将变量声明为extern时,您告诉编译器符号(可能)是您的翻译单元(c文件)的外部。

当你尝试在没有 extern的情况下声明变量时,值得注意的是,变量也定义了,例如:

 /* Declares, but does not defines external symbol 'foo' */
 extern int foo;

 /* Both declares AND defines bar */
 int bar;

这与函数的工作方式不同,声明的“默认”语法没有定义函数:

 /* Declare, but don't define spam */
 void spam(void);

 /* Declare, but don't define eggs */
 extern void eggs(void);

 /* Declare & define 'cheese' */
 void cheese(void){ return; }

所以你的例子看起来应该更像这样:

<强> qwe.h:

#ifndef QWE_H
#define QWE_H
/* Declare qwe here */
extern int qwe;
#endif

<强>在f1.c:

/* DEFINE qwe here */
int qwe = 1;

<强> f2.c:

#include "qwe.h"  /*header includes the `extern int qwe` declaration */
void my_function(void)
{
   /* use external symbol here! */
   qwe = 10;
}

答案 2 :(得分:2)

范围界定系统并不令人困惑。规则如下:

  • 如果在.c文件中定义某些内容,程序中的其他任何.c文件都可以访问它(它放在全局命名空间中)。

  • 如果在其定义前面指定static,那么只有SAME文件中的内容才能看到它。这应该是您不希望其他.c文件能够访问的所有函数和变量的默认位置。

非常重要的是要记住,extern只告诉编译器当前文件中没有定义有问题的变量/函数。这可以防止编译器发出错误,因为它无法找到符号,但它与作用域无关 - 您的.c文件可以看到全局命名空间中的所有内容,如果您没有按照第二部分规则你会在链接时快速了解这一点。

头文件同样与范围无关。它们只是放置一堆外部语句和宏的便利位置。

答案 3 :(得分:1)

  

我在标头中定义了qwe,在f1.c中声明了它。那是对的吗?

不,它应该是相反的方式。你应该在一个翻译单元中定义一个全局变量(那个geek代表一个.C文件),但是你可以根据需要在尽可能多的翻译单元中声明它。由于标题可能包含在许多翻译单元中,因此声明会放在标题中。

  

我什么时候应该在源文件中使用#include?

当标题包含翻译单元编译所需的任何内容时,您可以执行此操作,只有极少数例外。请注意,在某些情况下,可能需要或希望手动进行前向声明而不包括标题。

  

另外,如果我在函数内部将变量定义为静态,如static int i = 0;当函数存在时,该变量不会被销毁,它将保留它的内存和数据。

这是正确的,函数内部的静态变量只会被赋予初始值一次,并且只要程序继续运行,就会保留为其赋值的值。

答案 4 :(得分:1)

在C中,您应该使用头文件来声明数据,而不是定义数据。您不希望在标头中定义全局数据,因为它将在多个模块中进行冗余定义。标题向多个模块指示某处存在某些数据或函数及其类型,以及常见常量和宏(#define s)。除此之外,C中的东西非常简单。除了你声明它static之外,几乎任何东西在技术上都是全局的,保持它的范围是定义的模块。标题和函数中数据的extern声明原型帮助编译器知道特定模块正在访问这些项以及访问的数据类型,以便生成正确的代码。

你有:

  • 两个函数f1f2在单独的模块中定义,但在main使用。所以这些需要在头文件中声明

  • 在多个模块中使用的全局数据项qwe

  • 在一个模块中使用 static qwe

假设您希望使用一个头文件完成此操作(您可能需要单独的f1f2和全局数据 - 请参阅下文),您可以设置 你的标题为:

#ifndef MY_HEADER_H
#define MY_HEADER_H

extern int qwe;

void f1(void);
void f2(void);
#endif // MY_HEADER_H

然后在main.c

...
#include "my_header.h"

int qwe;    // This is global and can be accessed from other modules

void main(...)
{
    // call f1
    // call f2
   ...

我刚刚在qwe中任意定义了全局变量main.c。如果你有几个全局变量,你可以在他们自己的glob_data.c模块中定义它们,并拥有它自己的标题glob_data.h,以声明glob_data.h标头,以便可以在该模块上正确地进行编译以访问该数据。将全局数据保存在单独的头文件中有助于处理您拥有static数据实例与全局数据的情况,这些实例存在冲突。如果要使用static项进行编译,可以避免包含该全局项的数据头文件。

然后在您的C档案中,f1.c

...system headers included...
#include "my_header.h"

void f1() {
    printf("In f1: %d\n", qwe);
}

f2.c

...system headers included...
#include "my_header.h"  // Only if it doesn't contain `extern int qwe;`

static int qwe = 2;   // This hides the global qwe and is known only
                      // to f2.c

void f2(){
    printf("In f2: %d\n", qwe);
}

正如我上面提到的,您可能希望在单独的标头中分离您的函数原型和全局数据声明。这样,您可以仅包含每个模块中所需的内容并避免冲突,例如当您拥有static int qwe;与全局int qwe;时。