我有一个文件,我有一个全局数组
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
,这是错误的吗?
答案 0 :(得分:1)
当您在标题中声明变量时,您是否记得将其标记为extern
?您需要这样做,否则会发生的事情是您只是在包含标题的每个文件中获得一个新变量。请记住,#include
只是一个复制和粘贴工作;预处理器只是将头文件中的文本插入到包含发生的位置。如果头文件中的文本是char name[6]
,那么这就是你得到的;您的来源中显示char name[6]
的文字,导致变量name
与您在其他源文件中的变量无关。
如果将其标记为extern
,则链接器将抱怨未找到该符号。这意味着name
的定义不能是static
,因为这会导致链接器无法找到它。
因此,在头文件中,您需要此声明:
extern char name[6];
在您的源文件中,您需要以下定义:
char name[6];
回答实际问题:是的,它非常安全。
答案 1 :(得分:0)
原来是由于不同线程中的堆栈溢出造成的,将其标记为静态会将其放入bss部分,就在堆栈后面会溢出。
答案 2 :(得分:-1)
静态关键字对函数和变量意味着不同。
默认情况下,函数是“extern”,即它们的入口点由编译器公开,因此链接器可以找到它们,并且可以从任何已编译的模块调用它们。 如果你在函数声明的前面加上'static',那么该函数将不再公开,即它只能在同一个源模块中知道。
'static'关键字在用于变量(*)时具有非常不同的含义。它使它们不可更改。 当你说'static char name [6]'时,你告诉编译器你无意改变'name'的值。
在PC上运行的Linux上,这并不意味着什么。您告诉编译器您不会更改该值,然后更改它。你撒谎。没什么大不了的。
某些微控制器具有内部闪存,可用于运行代码,并保持固定(常量!)数据。 编译器和链接器使用您的“名称”不会更改的承诺,并将变量保留在闪存中。 您可以想象当您尝试更改它时会发生什么(不)。
更准确地说,编译器会将所有静态变量放在类似.const部分的内容中,然后链接器会将该部分放在闪存中。
(*)有一种方法可以查看'const',使其在用于变量和函数时具有相同的含义。这里不重要。