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