在C/ c++中,全局变量像我的教授认为的那样糟糕吗?


当前回答

在多线程应用程序中,使用局部变量代替全局变量以避免竞态条件。

当多个线程访问共享资源时,至少有一个线程对数据有写访问权,就会发生竞争条件。然后,程序的结果是不可预测的,它取决于不同线程访问数据的顺序。

更多信息请访问https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code

其他回答

我的教授曾经说过这样的话:使用全局变量是可以的,如果你使用正确的话。我不认为我能正确地使用它们,所以我很少使用它们。

The problem that global variables create for the programmer is that it expands the inter-component coupling surface between the various components that are using the global variables. What this means is that as the number of components using a global variable increases, the complexity of the interactions can also increase. This increased coupling usually makes defects easier to inject into the system when making changes and also makes defects harder to diagnose and correct. This increase coupling can also reduce the number of available options when making changes and it can increase the effort required for changes as often one must trace through the various modules that are also using the global variable in order to determine the consequences of changes.

封装的目的(基本上与使用全局变量相反)是减少耦合,以便更容易理解和更改源,更安全,更容易测试。当不使用全局变量时,使用单元测试要容易得多。

For example if you have a simple global integer variable that is being used as an enumerated indicator that various components use as a state machine and you then make a change by adding a new state for a new component, you must then trace through all the other components to ensure that the change will not affect them. An example of a possible problem would be if a switch statement to test the value of the enumeration global variable with case statements for each of the current values is being used in various places and it so happens that some of the switch statements do not have a default case to handle an unexpected value for the global all of a sudden you have undefined behavior so far as the application is concerned.

另一方面,可以使用共享数据区域来包含一组在整个应用程序中引用的全局参数。这种方法通常用于占用内存较少的嵌入式应用程序。

当在这类应用程序中使用全局变量时,通常将写入数据区域的职责分配给单个组件,所有其他组件都将该区域视为const并从中读取,而从不写入。采用这种方法会限制可能出现的问题。

一些全局变量的问题需要解决

当一个全局变量(比如struct)的源代码被修改时,使用它的所有内容都必须重新编译,以便使用该变量的所有内容都知道它的真实大小和内存模板。

如果有多个组件可以修改全局变量,则可能会遇到全局变量中数据不一致的问题。对于多线程应用程序,您可能需要添加某种类型的锁定或关键区域来提供一种方法,以便一次只有一个线程可以修改全局变量,并且当一个线程正在修改变量时,所有的更改都已完成,并在其他线程可以查询或修改变量之前提交。

调试使用全局变量的多线程应用程序可能会更加困难。您可能会遇到竞争条件,从而产生难以复制的缺陷。当多个组件通过一个全局变量进行通信时,特别是在多线程应用程序中,要知道哪个组件在何时以及如何更改变量是非常难以理解的。

Name clash can be a problem with using of global variables. A local variable that has the same name as a global variable can hide the global variable. You also run into the naming convention issue when using the C programming language. A work around is to divide the system up into sub-systems with the global variables for a particular sub-system all beginning with the same first three letters (see this on resolving name space collisions in objective C). C++ provides namespaces and with C you can work around this by creating a globally visible struct whose members are various data items and pointers to data and functions which are provided in a file as static hence with file visibility only so that they can only be referenced through the globally visible struct.

In some cases the original application intent is changed so that global variables that provided the state for a single thread is modified to allow several duplicate threads to run. An example would be a simple application designed for a single user using global variables for state and then a request comes down from management to add a REST interface to allow remote applications to act as virtual users. So now you run into having to duplicate the global variables and their state information so that the single user as well as each of the virtual users from remote applications have their own, unique set of global variables.

使用c++命名空间和C的结构体技术

对于c++编程语言,命名空间指令在减少名称冲突的可能性方面有很大的帮助。命名空间、类和各种访问关键字(私有、受保护和公共)提供了封装变量所需的大部分工具。然而,C编程语言并没有提供这个指令。这篇stackoverflow文章,C中的命名空间,提供了一些C语言的技术。

一种有用的技术是将单个内存常驻数据区域定义为具有全局可见性的结构体,该结构体中包含指向正在公开的各种全局变量和函数的指针。全局变量的实际定义是使用static关键字指定文件范围的。如果你使用const关键字来指示哪些是只读的,编译器可以帮助你强制执行只读访问。

使用struct技术还可以封装全局变量,使其成为一种恰巧是全局变量的包或组件。通过使用这种组件,可以更容易地管理影响全局和使用全局功能的更改。

然而,尽管命名空间或结构技术可以帮助管理名称冲突,但使用全局变量(尤其是在现代多线程应用程序中)所带来的组件间耦合的潜在问题仍然存在。

全局变量的问题是,由于每个函数都可以访问这些变量,因此越来越难以确定哪些函数实际读写这些变量。

为了理解应用程序是如何工作的,您几乎必须考虑修改全局状态的每个函数。这是可以做到的,但随着应用程序的增长,它将变得越来越困难,几乎不可能(或至少完全浪费时间)。

如果不依赖全局变量,则可以根据需要在不同函数之间传递状态。这样,您就有更好的机会理解每个函数的功能,因为您不需要考虑全局状态。

全局变量有多糟糕就有多糟糕。

如果您正在创建一个完全封装的程序,则可以使用全局变量。使用全局变量是一种“罪过”,但编程的罪过在很大程度上是哲学上的。

如果你看看洛杉矶。你会看到一种语言,它的变量是全局的。它是不可伸缩的,因为所有的库都只能使用全局变量。

也就是说,如果您有选择,并且可以忽略程序员的哲学,那么全局变量并不是那么糟糕。

Gotos也是,如果你使用得当的话。

最大的“坏”问题是,如果你使用错误,人们尖叫,火星着陆器坠毁,世界爆炸....或者类似的东西。

全局变量在小程序中很好,但如果在大程序中以同样的方式使用就很糟糕了。

这意味着你可以很容易地在学习中养成使用它们的习惯。这就是你的教授想要保护你的东西。

当你更有经验的时候,在他们没事的时候学习就更容易了。