1

我有一个文件,其中有一个全局数组

static char name[6];

和一个函数

static char* gen_name(char* dest, const size_t len) {
    for (int i = 0; i < len - 1; ++i)
        dest[i] = 'A' +  (genrand_uint32() % ('Z' - 'A'));
    dest[len - 1] = '\0';
    return dest;
}

然后将指向名称的指针存储在不同头文件中的全局变量中,该变量不是静态的。

this_name = gen_name(name, sizeof name);

当另一个文件中的函数使用这个指针时,它在 Linux 上运行良好,但是当我在微控制器上运行相同的代码时,它会打印垃圾。当我删除static关键字时,它工作正常。

为什么会这样?

我应该什么时候使用static?我想我应该将所有未在文件外使用的变量和函数声明为static,这是错误的吗?

4

3 回答 3

2

当您在标头中声明变量时,您是否记得标记它extern?你需要这样做,否则你只会在每个包含标题的文件中获得一个新变量。请记住,这#include只是一个复制和粘贴工作;预处理器只是将头文件中的文本插入到包含发生的位置。如果头文件中的文本是char name[6],那么这就是你得到的;源代码中的文本显示char name[6],导致变量name与您在其他源文件中的变量无关。

如果将其标记为extern,则链接器将抱怨找不到该符号。这意味着namecan't be的定义static,因为这会导致链接器无法找到它。

所以,在你的头文件中,你需要这个声明:

extern char name[6];

在你的源文件中,你需要这个定义:

char name[6];

并回答实际问题:是的,它非常安全。

于 2013-10-27T20:30:46.813 回答
0

结果证明是由不同线程中的堆栈溢出引起的,将其标记为静态会将其放在 bss 部分中,就在会溢出的堆栈后面。

于 2013-11-08T17:42:40.973 回答
-1

static 关键字对函数和变量意味着不同的东西。

函数默认为“extern”,即它们的入口点由编译器公开,因此链接器可以找到它们并且可以从任何已编译的模块中调用它们。如果你把'static'放在一个函数的声明前面,这个函数将不再是公共的,即它只会在同一个源模块中被知道。

'static' 关键字在用于变量(*)时具有非常不同的含义。它使它们不可更改。当您说“静态字符名称[6]”时,您是在告诉编译器您无意更改“名称”的值。

在 PC 上运行的 Linux 上,这并不意味着什么。你告诉编译器你不会改变这个值,然后你改变它。你撒谎。没什么大不了。

一些微控制器具有内部闪存,可用于从中运行代码并保持固定(恒定!)数据。编译器和链接器使用您的承诺,即“名称”不会更改并将变量留在闪存中。你可以想象当你试图改变它时会发生什么(不会发生)。

更准确地说,编译器会将所有静态变量放在类似 .const 的部分中,然后链接器会将该部分放在闪存中。

(*) 有一种方法可以查看“const”,这使得它在用于变量和函数时具有相同的含义。这里不重要。

于 2015-04-23T06:37:08.110 回答