我听说在C语言中编程时应该避免使用非常量全局变量,但是这真的是一种糟糕的做法吗?如果非常量全局变量是静态的,那也没关系吗?这是否使它更容易被接受?我所问的一个例子是在这个项目中。在这里,作者用C写了一个小的测试工具包,并使用全局静态变量来定义测试和失败的数量。这是好的做法还是应该避免这样的事情?
x7yiwoj41#
如果你有正确的判断,没有什么是不好的做法。但是全局变量确实有其缺点,你不应该在没有充分理由的情况下使用它们。全局变量的一个普遍问题是,它们会使代码更难正确测试,因为它依赖于全局状态。这也会使调试更难。正如Lundin在评论中提到的,在多线程程序中,你可能会遇到竞争条件的问题。也就是说,如果两个线程同时写入同一个变量。我听说在用C编程时应该避免使用非常量全局变量我想更深入地探讨一下这个问题的措辞,因为避免全局变量在其他语言中更重要,这些语言有很好的方法来解决它,而C语言往往缺乏这种方法。例如,让我们回到竞争条件的问题。假设你想要一个简单的计数器,就像你的例子一样。下面是一个非常简单的实现:
#include<pthread.h> int counter; pthread_mutex_t lock; void increaseCounter(void) { pthread_mutex_lock(&lock); counter++; pthread_mutex_unlock(&lock); }
字符串请注意,这是使用一个额外的全局,互斥锁。全局变量在C中很常见。errno是一个众所周知的变量,用于检查某些函数的成功或失败。
n7taea2i2#
通常认为最大限度地减少全局变量的使用并尽可能地将必要的变量显式传递给函数是一种良好的做法。1.* 过度使用全局变量 ,即使它们是静态的,也会使代码更难理解、调试和维护。它们会引入隐藏的依赖关系,并使跟踪修改发生的位置变得困难。1. 测试和测试 *:全局变量可能会使单元测试复杂化,因为它们会引入额外的状态,可能会影响不同函数的结果。当它们依赖于全局状态时,隔离和测试函数变得更加困难。在提供的示例中,作者使用全局常量(ltests和lfails)来跟踪测试运行的数量和测试失败的数量。您提供的项目是一个简单的项目,因此在这种情况下您可以使用全局变量,但在更大和更复杂的项目中,您应该避免使用它们。而不是使用C结构(structs)
lokaqttq3#
在检查代码时,我经常问自己的一个问题是在代码中,变量X在哪里得到它的值?如果你的变量X是全局变量,那么程序中的任何函数都可以改变它的值;你需要检查所有的代码来确定X是在哪里设置的。如果你以某种方式限制对X的访问,使得90%的函数不能改变它,这可能会使你的代码更容易理解!让你的全局变量static做到这一点-所有在你当前翻译单元(c文件)之外的函数都不能直接访问它(尽管它们仍然可以通过专用的函数参数访问它)。所以我敢肯定static global比常规的extern global更好。它使它更好吗?可能不是!你仍然可以通过使用适当的信息流(函数参数和文档)使它更好。
static
extern
aydmsdu94#
static在C中有两种含义,一种是作为存储类(当用于限定局部变量时),另一种是作为 * 链接说明符 *,当在您链接的项目中使用的函数外部使用时。静态链接意味着这些变量在声明它们的翻译单元之外不可见,因此它们实际上根本不是 global。“static global”在这个意义上是一个矛盾修饰法。当然,如果翻译单元的内聚性不够(比如 * 所有代码都在一个文件中 *),那么它们并不比真正的全局变量好,甚至本质上是一样的。然而,在这种情况下,模块是高度内聚的,而且相当小,只包含与测试功能相关的外部接口。所以在这种情况下,我会说它是合适的。这并不是说它总是如此。上下文就是一切。带有 * 静态存储类 * 的变量的一个问题(这是任何函数局部显式声明static,和 * 所有 * 变量声明外的一个函数,无论他们是否有 * 静态链接 *),是他们不是本质上线程安全的。同一个变量被所有线程使用,但是访问的定时和顺序可能是不确定的,单个变量可能不是原子的,并且相关变量的组可能不一致。关于全局变量的弊端以及如何避免全局变量的讨论,请参阅Jack Ganssle的A Pox in Globals。它与嵌入式系统有关,但普遍适用。使用静态链接的变量实际上是他的解决方案之一-在必要时使用访问函数进行受控的外部访问(尽管低耦合/高内聚设计可以最大限度地减少这种需求)
4条答案
按热度按时间x7yiwoj41#
如果你有正确的判断,没有什么是不好的做法。但是全局变量确实有其缺点,你不应该在没有充分理由的情况下使用它们。
全局变量的一个普遍问题是,它们会使代码更难正确测试,因为它依赖于全局状态。这也会使调试更难。
正如Lundin在评论中提到的,在多线程程序中,你可能会遇到竞争条件的问题。也就是说,如果两个线程同时写入同一个变量。
我听说在用C编程时应该避免使用非常量全局变量
我想更深入地探讨一下这个问题的措辞,因为避免全局变量在其他语言中更重要,这些语言有很好的方法来解决它,而C语言往往缺乏这种方法。
例如,让我们回到竞争条件的问题。假设你想要一个简单的计数器,就像你的例子一样。下面是一个非常简单的实现:
字符串
请注意,这是使用一个额外的全局,互斥锁。
全局变量在C中很常见。errno是一个众所周知的变量,用于检查某些函数的成功或失败。
n7taea2i2#
通常认为最大限度地减少全局变量的使用并尽可能地将必要的变量显式传递给函数是一种良好的做法。
1.* 过度使用全局变量 ,即使它们是静态的,也会使代码更难理解、调试和维护。它们会引入隐藏的依赖关系,并使跟踪修改发生的位置变得困难。
1. 测试和测试 *:全局变量可能会使单元测试复杂化,因为它们会引入额外的状态,可能会影响不同函数的结果。当它们依赖于全局状态时,隔离和测试函数变得更加困难。
在提供的示例中,作者使用全局常量(ltests和lfails)来跟踪测试运行的数量和测试失败的数量。您提供的项目是一个简单的项目,因此在这种情况下您可以使用全局变量,但在更大和更复杂的项目中,您应该避免使用它们。而不是使用C结构(structs)
lokaqttq3#
在检查代码时,我经常问自己的一个问题是
在代码中,变量X在哪里得到它的值?
如果你的变量X是全局变量,那么程序中的任何函数都可以改变它的值;你需要检查所有的代码来确定X是在哪里设置的。
如果你以某种方式限制对X的访问,使得90%的函数不能改变它,这可能会使你的代码更容易理解!让你的全局变量
static
做到这一点-所有在你当前翻译单元(c文件)之外的函数都不能直接访问它(尽管它们仍然可以通过专用的函数参数访问它)。所以我敢肯定
static
global比常规的extern
global更好。它使它更好吗?可能不是!你仍然可以通过使用适当的信息流(函数参数和文档)使它更好。aydmsdu94#
static
在C中有两种含义,一种是作为存储类(当用于限定局部变量时),另一种是作为 * 链接说明符 *,当在您链接的项目中使用的函数外部使用时。静态链接意味着这些变量在声明它们的翻译单元之外不可见,因此它们实际上根本不是 global。“static global”在这个意义上是一个矛盾修饰法。
当然,如果翻译单元的内聚性不够(比如 * 所有代码都在一个文件中 *),那么它们并不比真正的全局变量好,甚至本质上是一样的。
然而,在这种情况下,模块是高度内聚的,而且相当小,只包含与测试功能相关的外部接口。所以在这种情况下,我会说它是合适的。
这并不是说它总是如此。上下文就是一切。带有 * 静态存储类 * 的变量的一个问题(这是任何函数局部显式声明
static
,和 * 所有 * 变量声明外的一个函数,无论他们是否有 * 静态链接 *),是他们不是本质上线程安全的。同一个变量被所有线程使用,但是访问的定时和顺序可能是不确定的,单个变量可能不是原子的,并且相关变量的组可能不一致。关于全局变量的弊端以及如何避免全局变量的讨论,请参阅Jack Ganssle的A Pox in Globals。它与嵌入式系统有关,但普遍适用。使用静态链接的变量实际上是他的解决方案之一-在必要时使用访问函数进行受控的外部访问(尽管低耦合/高内聚设计可以最大限度地减少这种需求)