在头文件中定义一个变量,只有在没有 present extern 关键字的情况下才有效?
在头文件中定义一个变量,只有在没有 present extern 关键字的情况下才有效?
我目前正在学习C语言,但我真的不理解头文件是如何工作的,为了确保我有两个问题。
1)让我们来看一下下面的程序:main.c:
#include#include #include "functions.h" int main( void ) { printf( "Num = %d\n", number ); printNumber(); return 0; }
functions.c:
#include#include #include #include "functions.h" void printNumber( void ) { printf("Number = %d\n", number ); }
functions.h:
#ifndef FUNCTIONS #define FUNCTIONS int number; extern void printNumber( void ); #endif // FUNCTIONS
在头文件中,没有使用extern关键字,所以似乎没有引用到number,程序输出:
Num = 0 Number = 0
第一个问题是,number是否被初始化(如果number只在头文件中出现,那么number是全局变量或类似的变量吗)?这是合法的代码/程序吗?
第二种情况,让我们来看一下下面的代码:main.c:
#include#include #include "functions.h" int main( void ) { printf( "Num = %d\n", number ); printNumber(); return 0; }
functions.c:
#include#include #include #include "functions.h" void printNumber( void ) { printf("Number = %d\n", number ); }
functions.h:
#ifndef FUNCTIONS #define FUNCTIONS extern int number; extern void printNumber( void ); #endif // FUNCTIONS
这里程序将无法编译,因为会出现“undefined reference to number”的错误。
这迫使我在main中声明number:
#include#include #include "functions.h" int number; int main( void ) { printf( "Num = %d\n", number ); printNumber(); return 0; }
这是正确的方式,为什么呢?
最后,为什么对于void printNumber( void )也不适用extern关键字呢?我看到无论有没有extern关键字,它都能正常工作。
在上述内容中,问题的出现是因为在头文件中定义变量时,只有在没有使用extern关键字的情况下才起作用。解决方法是在头文件中添加宏定义,并在主文件中使用宏来声明变量,这样在主文件编译时会为变量分配存储空间,而在其他源文件中,变量将被声明为extern。这样可以使变量只在主文件中可见,而在其他源文件中不可见。如果需要在主文件中使用在头文件中定义的变量,可以在主文件中重新定义这个变量,并使用static关键字来限制其作用范围。然而,需要注意的是,如果在头文件中重新定义这个变量,就会出现错误:static declaration of ‘number’ follows non-static declaration。因此,应该只在主文件中重新定义变量,而不再在头文件中进行定义。
问题的出现原因是在头文件中定义了变量,这意味着包含该头文件的每个翻译单元都会有该变量的定义。然而,这是不允许的,因为你只能在所有翻译单元中分散定义一个变量。
解决这个问题的方法是在头文件中声明变量,而不是定义变量。使用关键字extern标记它为声明而不是定义,编译器将知道该变量在其他地方定义。
然后你当然需要在一个单独的源文件中进行定义。在一个单一的源文件中进行定义,比如:
int number;
这就是你在最后一个变体中做的事情。
很多工具链和我认为posix允许多个定义...
所以这意味着如果我在main中声明int number,在functions.c中也不需要再声明了吗?这对函数也一样吗?
是的,如果你在functions.c中显式定义了它,你将面临多个定义的问题。对于函数也是一样的。
从未听说过 tentative definitions?
所以这意味着如果我在头文件中对所有变量和函数使用extern关键字,就没有问题了。谢谢。
函数默认是extern的,不需要显式指定。你可以通过将它们声明为static来使它们“局部”于翻译单元(.c文件)。
我明白了。很遗憾我不能为这个问题点赞,因为声望不到15。
不,没关系,因为第一段已经是错的。
extern void f(void);和void f(void);之间有一些微小的区别。第一个是声明,第二个是原型。
第一个只是声明,还是声明和原型都包括在内。我指的是它在头文件中的存在。