主文件(prog.c):
#include "log.c"
#include "library.c"
static char * Foo;
如果在主文件(prog.c)中定义了某个变量(char * Foo),并且从library.c调用的log.c函数需要它,那么如何正确地声明Foo从log.c的名称空间中可见?
答案 0 :(得分:3)
将其声明添加到.c文件中包含的某个.h文件中。在其中一个文件中定义它。
当然,无法将其声明为static
,因为static
关键字是一个承诺,在该特定模块之外不需要该名称。
例如,在prog.h
:
extern char *Foo;
prog.c
中的:
#include "prog.h"
#include "log.c"
#include "library.c"
char * Foo; // make sure that Foo has a definition
// some code probably wants to make Foo have a value other than NULL
log.c
中的:
//... other includes
#include "prog.h" // and now Foo is a known name
// some code here is using the global variable Foo
现在,这是坏消息。
执行此类操作会在prog.c
和log.c
模块之间创建耦合。这种耦合增加了整个应用程序的维护成本。一个原因是没有办法阻止其他模块也使用全局变量。更糟糕的是,他们可能会完全意外地使用它,因为它的名称描述性不够。
更糟糕的是,全局变量使得从单线程程序转向多线程程序变得更加困难。可能从多个线程访问的每个全局变量都是很难诊断错误的潜在来源。解决方法是保护必须是同步对象的全局信息,但过度使用会导致应用程序中除了当前使用全局线程之外的所有线程都被阻塞,使多线程应用程序有效地单线程化。
有时候全局变量隐含的模块间耦合是可以接受的。一个用例适用于通用应用程序范围的选项。例如,如果您的应用程序支持--verbose
选项,使其在工作时发出喋喋不休的声音,则选项设置的标志在整个代码中进行测试将是一个全局变量。
在SO上肯定存在一些问题,即深入研究全局变量的缺陷,并为其合理使用提供指导。
答案 1 :(得分:2)
将库源代码包含在主程序中是常规的:
#include "log.c"
#include "library.c"
static char * Foo;
(需要分号。)
但是,鉴于您正在做的事情,如果“log.c”需要查看声明,您可以这样做:
static char * Foo;
#include "log.c"
#include "library.c"
现在静态声明对“log.c”(和“library.c”)可见。
如果你选择更传统的设置,那么你可以让“log.c”中的代码访问在适当的头文件中声明的全局变量(而不是文件静态变量)。但是,这种依赖关系(库文件依赖于全局变量)是一种麻烦。主程序(或某些代码)必须提供变量定义。最好让“log.c”中的代码定义变量,并且(假定的)标题“log.h”将声明变量,然后主程序将相应地设置变量。或者,更好的是,“log.c”中的代码将提供一个函数或几个函数来操作变量,标题将声明这些函数,主程序将使用它们。
答案 2 :(得分:1)
你想要extern。当您对变量名称进行extern时,您正在做出一个“承诺”,即链接时该变量将存在。您希望将其存储在.c文件中,但在标题中将其外部存储。这样,它只是在.c的目标文件中实例化一次。您不希望有两个不同的.o使用相同的名称来引用内存中的不同位置。 (如上所述,为图书馆要求这样的东西几乎总是不好的形式。)
所以在一个共同的标题中你有
COMMON.H
extern Foo bar;
然后在prog.c
Foo bar;
当你在log.c中包含common.h时,你可以从prog.c中访问bar。
请注意,静态在C中与在Java中非常不同。在Java中,它是一个全局的类,可供任何人使用,即使没有该类的实例。在C中,静态意味着变量在编译单元外部不可见。
答案 3 :(得分:1)
简单的答案是:
static char * Foo;
#include "log.c"
#include "library.c"
这使Foo
在log.c和library.c中可见,仅仅是因为“使用前声明”规则。
然而,您真正需要知道的是,这是讨厌的代码!您已经提交了至少两个罪; Use of global variables并且未能理解使用separate compilation and linking。