【问题标题】:What is the most elegant way to work with global variables?使用全局变量最优雅的方式是什么?
【发布时间】:2018-10-26 11:58:02
【问题描述】:

几年前,我了解到全局变量不好,应该避免使用。但我知道它们有时是不可避免的,至少在嵌入式系统中是这样。您认为与他们合作最优雅的方式是什么?

在我的项目中,我有一个名为 globals.h 的文件,我在其中定义了所有全局变量:

#ifndef GLOBALS_H
#define GLOBALS_H
extern int16_t    gVariable1;
extern int16_t    gVariable2;
….
#endif

在我的主项目文件中,我声明了所有全局变量:

/*
***********************************************************************
*                            global variables                         *
***********************************************************************
*/
    int16_t     gVariable1 = 0;
    int16_t     gVariable2 = 0;


int16_t main (void)
{
    gVariable1 = 6;

    //  do other stuff
}

并且知道我在需要访问全局变量的项目的每个其他文件中都包含globals.h

这很好,但是有没有更优雅的方法来处理它?

【问题讨论】:

  • 这是正确的,除非您决定将全局变量分开,以便一组在header1.h 中声明并在source1.c 中定义,而第二组在header2.h 中声明并在source2.c(或分成两组以上的文件)。您可能会在How do I use extern to share variables between source files? 中找到一些想法,但坦率地说,您已经有了核心想法——在头文件中声明变量,并在特定的源文件中定义它们,并在需要访问任何变量的任何地方使用头文件。跨度>
  • 请注意,优雅不应成为最终目标。典型的目标是使程序执行某些功能或提高性能。优雅是一种工具。优雅通常与良好的设计相一致,它还有助于人们更容易理解、记住和使用软件(并享受工作)。因此,当它服务于有用的目的时,寻求对全局变量的优雅管理是很好的。但优雅只是一种工具;当一些相互冲突的需求出现时,我们不应该坚持。

标签: c coding-style global-variables


【解决方案1】:

我不确定全局变量在所有情况下都是不好的,但您确实需要努力使它们很少(否则,您的代码将无法阅读)。比如<stdio.h>stdout,换成FILE*get_standard_output(void);的getter函数也不会更好。

根据经验,避免在整个程序中使用超过 4 或 5 个全局变量(回想一下 magical number seven 作为我们认知限制的提示)。

但是,您可以将几个 相关 全局变量打包(巧妙且具有良好品味,以保持代码可读性)到单个 struct 类型的全局变量中。以您的示例为例,这可能意味着您的globals.h

struct globalstate_st { int16_t v1, v2; };

然后

extern struct globalstate_st gs;

你会使用gs.v1而不是gVariable1;如果使用优化编译,使用gs.v1的性能相当于使用gVariable1

顺便说一句,如果您有一个多线程程序,您通常应该使用一些mutex(或其他某种同步或原子性)来保护全局数据。考虑阅读this pthread tutorial

【讨论】:

    【解决方案2】:

    全局变量并不危险。它有帮助。但最佳实践是始终限制变量的范围。

    用静态和暴露函数设置全局变量以获取和设置值。

    例如:在 global.c 中

    static int gMyGlobalVariable;
    
    int getMyGlobalVariableValue()
    {
       return gMyGlobalVariable;
    }
    
    void setMyGlobalVariableValue(int set)
    {
       gMyGlobalVariable = set;
    }
    

    例如:在 global.h 中

    void setMyGlobalVariableValue(int set);
    int getMyGlobalVariableValue();
    

    这将更好地控制多线程情况。

    【讨论】:

    • 这不是一个真正的“全局”变量,因为它在整个项目中并不全局可用。形式上,它是一个具有内部链接的文件范围变量。这很好,特别是在单核嵌入式系统中。不像extern,它使变量“全局”。
    • 全局变量很危险,因为它们增加了出错的机会。在理想的编程中,它们被正确使用并且对性能或行为没有影响。然而,人类并不理想。他们会犯错,应该尽量减少犯错的机会。
    • 这会将对全局变量的每次访问更改为函数调用(大多数工具链无法跨单元内联),从而增加了空间和时间。问题提到了嵌入式系统,其中空间和时间可能很宝贵。使用访问函数通过强制访问以函数调用的形式部分地限制了范围,因此当它用于全局变量时,不能将简单标识符与局部标识符混淆。但这并没有真正限制范围,因为在任何地方都可以访问。只需对变量进行明确命名即可达到相同的效果。
    • 请注意,上面的注释忽略了多线程,这在答案的最后一句中提到了,但未反映在显示的代码中。如果涉及多线程问题,问题就会改变。
    猜你喜欢
    • 2022-01-01
    • 2011-06-05
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2016-09-18
    • 2017-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多