我开始为产品编写固件,我是这里的新手。我浏览了许多关于不使用全局变量或函数的文章。在8位系统中使用全局变量是否有任何限制,还是完整的“否”。如何在系统中使用全局变量,或者应该完全避免使用全局变量?
我想就此主题向大家提出宝贵的建议,以使我的固件更紧凑。
static
文件作用域与“全局”作用域不同,请参阅下面的答案。
我开始为产品编写固件,我是这里的新手。我浏览了许多关于不使用全局变量或函数的文章。在8位系统中使用全局变量是否有任何限制,还是完整的“否”。如何在系统中使用全局变量,或者应该完全避免使用全局变量?
我想就此主题向大家提出宝贵的建议,以使我的固件更紧凑。
static
文件作用域与“全局”作用域不同,请参阅下面的答案。
Answers:
只要牢记@Phil的准则,就可以成功使用全局变量。但是,这里有一些不错的方法来避免它们的问题,而不会使编译后的代码紧凑。
将局部静态变量用于只需要在一个函数内部访问的持久状态。
#include <stdint.h>
void skipper()
{
static uint8_t skip_initial_cycles = 5;
if (skip_initial_cycles > 0) {
skip_initial_cycles -= 1;
return;
}
/* ... */
}
使用结构将相关变量保持在一起,以使其更清楚地在何处使用和不应该使用它们。
struct machine_state {
uint8_t level;
uint8_t error_code;
} machine_state;
struct led_state {
uint8_t red;
uint8_t green;
uint8_t blue;
} led_state;
void machine_change_state()
{
machine_state.level += 1;
/* ... */
/* We can easily remember not to use led_state in this function. */
}
void machine_set_io()
{
switch (machine_state.level) {
case 1:
PIN_MACHINE_IO_A = 1;
/* ... */
}
}
使用全局静态变量使变量仅在当前C文件中可见。这样可以防止由于命名冲突而导致其他文件中的代码意外访问。
/* time_machine.c */
static uint8_t current_time;
/* ... */
/* delay.c */
static uint8_t current_time; /* A completely separate variable for this C file only. */
/* ... */
最后一点,如果要在中断例程中修改全局变量并在其他地方读取它:
volatile
。要么
volatile
变量的常规用法是允许在一个执行上下文中运行的代码让另一执行上下文中的代码知道发生了什么。在8位系统上,可以使用一个易失性字节来管理缓冲区,该缓冲区将保留不超过128的2的幂的字节数,该易失性字节指示放入缓冲区的总生命周期字节数(mod 256)和另一个表示取出的生命周期字节数,条件是只有一个执行上下文将数据放入缓冲区,而只有一个执行上下文从缓冲区中取出数据。
您不应该完全避免使用全局变量(简称“全局变量”)。但是,您应该明智地使用它们。过度使用全局变量的实际问题:
将前缀添加g_
到全局变量的名称是一个好习惯。例如,g_iFlags
。当您在代码中看到带有前缀的变量时,您会立即意识到它是全局变量。
static
标志将如何变为可见main()
?您是在暗示具有的相同函数static
可以将其返回给main()
以后吗?
嵌入式工作中全局数据结构的优点是它们是静态的。如果您需要的每个变量都是全局变量,那么在输入函数并在堆栈上为它们腾出空间时,您绝不会意外耗尽内存。但是,那时候为什么要有功能呢?为什么不提供一个能够处理所有逻辑和流程的大型函数-像不允许GOSUB的BASIC程序。如果您对这个想法有足够的了解,您将拥有一个典型的1970年代汇编语言程序。高效,不可能维护和排除故障。
因此,请谨慎使用全局变量,例如状态变量(例如,是否每个函数都需要知道系统是否处于解释或运行状态)以及许多函数都需要查看的其他数据结构,就像@PhilFrost所说的那样,您的功能可预测?是否有可能用永不结束的输入字符串填充堆栈?这些是算法设计的问题。
请注意,static在函数内部和外部具有不同的含义。 /programming/5868947/difference-between-static-variable-inside-and-outside-of-a-function
/programming/5033627/static-variable-inside-of-a-function-in-c
全局变量仅应用于真正的全局状态。仅当只能有一个“地图的北边界”时,使用全局变量来表示诸如地图北边界的纬度之类的内容。如果将来代码可能必须与具有不同北部边界的多个地图一起使用,则可能需要对使用针对北部边界使用全局变量的代码进行重新设计。
在典型的计算机应用程序中,通常没有特殊的理由认为某物永远不会超过一种。但是,在嵌入式系统中,这样的假设通常更为合理。虽然可能会调用典型的计算机程序来支持多个同时用户,但典型的嵌入式系统的用户界面将设计为由单个用户与其按钮和显示进行交互来进行操作。这样,它将在任何时候具有单个用户界面状态。设计系统以使多个用户可以与多个键盘和显示器进行交互,这比为单个用户设计系统要复杂得多,并且实现时间要长得多。如果从不要求系统支持多个用户,为促进这种使用而投入的任何额外努力将被浪费。除非可能需要多用户支持,否则比花额外的时间添加多用户支持(可能永远不需要)。
嵌入式系统的一个相关因素是,在许多情况下(尤其是涉及用户界面),支持具有多个功能的唯一实用方法是使用多个线程。在没有其他对多线程的需求的情况下,使用简单的单线程设计可能比使用真正不需要的多线程来增加系统复杂性更好。如果要添加多个功能,则无论如何都需要重新设计庞大的系统,也不需要重新使用某些全局变量就可以了。
许多人对此主题感到困惑。全局变量的定义为:
可以从程序中的任何地方访问的东西。
这与文件范围变量不同,后者由关键字声明static
。这些不是全局变量,它们是局部私有变量。
int x; // global variable
static int y; // file scope variable
void some_func (void) {...} // added to demonstrate that the variables above are at file scope.
您应该使用全局变量吗?在某些情况下还可以:
在任何其他情况下,您永远都不要使用全局变量。从来没有理由这样做。而是使用文件作用域变量,这是完全可以的。
您应该努力编写旨在完成特定任务的独立的自治代码模块。在这些模块内,内部文件范围变量应作为私有数据成员驻留。这种设计方法被称为面向对象,被广泛认为是好的设计。
.data
段。