在C语言中使用静态变量的最佳实践

10

全局变量通常被认为是一种不良的编程实践。

在C语言中,具有模块(文件)作用域的静态变量是否被认为是可以接受的?

我的想法是,在面向对象的语言中,成员变量可能比C语言中的静态变量更加安全,而且成员变量似乎被认为是一件好事。

我厌倦了通过多个函数传递参数,并且可以看到使用静态变量的吸引力,特别是如果它们是const

但我很想知道这是否被视为不良实践,以及一个具有成员变量并在其多个方法中使用的大型对象与包含几个使用静态变量的函数的C文件之间是否真的存在编程错误的级别差异?


2
为什么要关闭它?这是一个很好的、具体的问题,很多程序员都应该感兴趣。 - Lundin
1
非常感谢在问题关闭之前提供的答案 - 它们帮助我澄清了问题。 - bph
1
真是不可思议,他们因为“不具建设性”而关闭这样的问题,但在每个“有建设性”的答案上,人们都会插入“但你不应该这样做,你应该这样做,因为是的,在现实世界中我们就是这样做的”。 - Jose V
“好的” Stack Overflow 问题的范围实际上相当狭窄,边界得到了严格的执行。我认为这可能也是我的第一个问题,而且管理员对那些声望非常低的人更加严格! - bph
6个回答

5

C语言中的静态(文件作用域)变量类似于C ++中的静态成员变量。

任何使用非const静态变量进行函数间通信都会使那些函数不可重入和线程不安全。因此,通常最好通过参数传递信息。

非静态成员变量的更好类比是结构体成员。只需在结构体中收集您的“成员变量”,并将该结构体作为“this”参数传递即可。


2

区别在于:使用成员变量时,您可以拥有多个对象,每个对象都有自己的成员变量。使用模块范围的静态变量,则只有一个实例。

如果要比较模块级静态变量和静态类成员变量,则没有真正的大区别。两者都只实例化一次,只是作用域和访问规则不同。


2
使用静态变量的一个大弊端是“副作用”,即函数的结果不仅依赖于输入参数,这使得测试和调试变得更加困难。没有副作用的函数更容易测试,因为您可以假设每次使用相同的参数集合调用函数时会得到相同的结果。
如果出现错误,您可以检查结果是否与输入参数相对应。如果您发现输入参数有误,则可以在代码中跟踪/找到错误的位置。如果函数依赖于静态变量并且静态变量的值不符合预期,那么如何跟踪/找到它是如何改变的?
因此,如果您想使用常量,请使用适当的常量(#DEFINE),或将参数分组到结构体中,并尽可能避免使用静态变量。(至少#DEFINE的值不会在内存中被破坏)

1

静态变量可能比全局变量稍微好一些,但并不多。然而,不像全局变量那样邪恶并不能算是什么值得称赞的事情!

当你有多个线程或可重入函数时,它们就不够用了。更重要的是,将它们用作参数传递机制会导致代码非常难以阅读和维护。静态变量有其用途,但我永远不会将它们用于参数传递。在某些情况下,将参数收集到结构体中以便传递可能更好。


确实,线程或可重入函数不应在没有同步对象的情况下访问静态变量,但这并不是静态变量本身的问题。此外,有很多像回调函数、中断等没有参数的东西。那么你别无选择,只能使用静态变量,无论你是写C还是C++。 - Lundin
@lundin的问题特别涉及使用模块静态作为参数传递的替代方案。 - David Heffernan
是的,那么为什么要引入多线程呢?原帖没有提到代码的平台或目的。 - Lundin

1

你可以使用全局或静态变量,但要小心使用。我不确定模块范围的静态变量是否比全局变量好多少。

特别是,在即使是大型程序中拥有超过十几个全局变量可能会被认为是不好的品味(但这种情况确实存在)。

而且,你可能更喜欢将静态或全局数据分组在较大的struct中。


为什么会是不好的编程习惯呢?它们被私有地封装,不会污染全局命名空间。 - Lundin
关于糟糕的编程风格,我在想全局变量(而非静态变量)。你可以通过指针传递静态变量,但有时可能会出现一些奇怪的与此相关的错误。当然,这取决于情况... - Basile Starynkevitch

1
在你尝试使用它们的上下文中,模块变量可能不是一个好主意。通过参数传递所有内容的好处在于很难使方法调用与之不同步。每个方法都会执行某些操作并将其组件传递给另一个方法,因此很容易进行跟踪 - 变量仅在方法调用期间存在。如果变量存在于其他地方,则调试变得更加困难 - 例如使用过时变量的事情从不可能变为相当可能。
静态变量通常用作标志 - 其中一个常见的标志是布尔值,您可以设置它以微妙的方式改变整个模块的模式(类似于内置的DEBUG)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接