C语言 如何声明静态变量但不定义它

ubby3x7f  于 12个月前  发布在  其他
关注(0)|答案(7)|浏览(137)

有些时候我们需要预先声明一个静态变量,然后使用它。但是这个声明的变量名可能是错误的,编译器无法检测到它,哎呀!
范例:

/* lots of codes */
static some_type some_name; /* pre-declaration */
                            /* but it may define "some_name" */
/* use some_name */

/* lots of codes */

static some_type someName = initialization; /* definition */
/* use someName */

/* lots of codes */

字符串
“some_name”和“someName”是不同的,我们在开始使用了一个错误的变量。如果预声明语句没有定义任何东西,编译器会发现错误。
那么,如何声明一个静态变量而不定义它呢?如何将预声明改为一个新的,使编译器可以检测到错误的名称?

qvtsj1bj

qvtsj1bj1#

gcc将在您描述的情况下给出给予警告:

./x.c:3010: warning: 'someName' defined but not used

字符串
解决方案:做你现在正在做的事情,但不要忽略编译器警告;)

编辑:

关于你更新的问题:不,我不相信有一种方法可以简单地声明一个静态变量(而不定义它)。
常见的解决方案是确保所有的全局作用域变量只声明一次,如果需要,可以使用初始化器。

1cosmwyk

1cosmwyk2#

static some_type some_name; /*definition */

字符串
静态变量some_name已经初始化为0;它是定义,而不仅仅是声明。
IMO,静态变量不能在C中使用外部说明符声明,因为它的链接总是内部的。

kxkpmulp

kxkpmulp3#

在C语言中,不可能为具有内部链接的对象创建非定义声明(即术语中的“预声明”)。
最接近的是一个 * 临时定义 *,这就是你在例子中所做的。但是如果输入错误,临时定义将隐含地产生一个独立的定义,而不是链接器错误。

v6ylcynt

v6ylcynt4#

一点背景:
正如其他人所指出的,静态变量是有内部链接的,这意味着它们只能在同一个“编译单元”或源文件中使用。这意味着你不能在头文件中声明它,在一个编译单元中赋值,然后期望这个值出现在另一个编译单元中。
当你初始化一个全局变量(静态或非静态)时,编译器只是将初始值放入可执行文件中为变量分配的内存位置。换句话说,它总是有一个初始值。当然,你总是可以在以后使用赋值语句重写该值。
建议:
如果你在编译时真的不知道变量的值,那么你应该在初始化函数中动态地赋值。

static some_type some_variable; /* = 0 by default */

/* some code */

void MyInitializations()
{
    some_variable = some_value;
}

字符串
如果你想在一个地方声明变量,比如头文件,并在源文件中定义它,那么你应该使用“extern”声明,它告诉编译器不用担心变量在哪里。链接器会找到变量的位置,就像它在另一个文件中找到一个函数一样,并填写地址。
标题:

extern some_type some_variable;


源文件1:

void UseSomeVariable()
{
    x = some_variable;
}


源文件2:

some_type some_variable = some_value;

/* possible also uses some_variable */


如果你只想在一个地方声明变量,在另一个地方定义它,不要使用'static'关键字。这样做的缺点是,你不能在不同的编译单元(.c文件)中使用同一个全局变量,也不能在头文件中使用它。

ttcibm8c

ttcibm8c5#

你需要预先声明变量吗?如果不需要,那么把初始化器放在唯一的声明上。如果你的初始化器不是一个常量(这需要C++,而不是C,IIRC),那么我可以理解为什么你需要在使用它的一些函数之前预先声明它。但是这样你需要的初始化器的所有东西都可以在它之前预先声明。
所以把常量def和静态变量放在每个文件的顶部,这样静态变量的初始化器就可以放在常量后面,这样就不需要单独的初始化行了。
在任何其他情况下,caf都是对的:用gcc编译代码只是为了获得它的警告的好处,这是值得的。我已经为g用C编写的MFC GUI做了这件事。(编译,而不是运行!)
AFAIK C没有办法编写弱定义,如果后面没有带有初始化器的定义,则会产生错误。始终存在隐式0,因为变量位于BSS部分。

q7solyqu

q7solyqu6#

在C++中(而不是C),可以使用未命名的命名空间而不是static.Decliter来完成,如下所示:

namespace {
    extern some_type some_name;
}

字符串
extern没有定义,但由于未命名的名称空间,some_name无论如何都有内部链接,就像声明为static一样(参考:https://en.cppreference.com/w/cpp/language/storage_duration#Linkage)。
相应的定义很简单:

namespace {
    some_type some_name = initialization;
}

ki1q1bka

ki1q1bka7#

如果我理解你的问题,也许你只是没有正确地面对它。
如果你用extern SomeType someVar_;会更好,它对你的程序说,我知道这个变量是已知的,但我现在不想告诉你它是什么。
因此,您可以在一个单独的文件中声明您的变量,
static SomeType SomeVar_;
在你的档案里,
extern SomeType SomeVar_
然后把初始化放在你想要的任何地方。

相关问题