在C/ c++中,全局变量像我的教授认为的那样糟糕吗?
当前回答
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技术还可以封装全局变量,使其成为一种恰巧是全局变量的包或组件。通过使用这种组件,可以更容易地管理影响全局和使用全局功能的更改。
然而,尽管命名空间或结构技术可以帮助管理名称冲突,但使用全局变量(尤其是在现代多线程应用程序中)所带来的组件间耦合的潜在问题仍然存在。
其他回答
绝对不是。但是滥用它们……这很糟糕。
出于某种原因而无意识地删除它们只是……盲目的。除非您知道其优点和缺点,否则最好避免使用全局变量,并按照您学到的方法进行操作,但全局变量并没有什么隐含的错误。当你了解了利弊后,最好自己做决定。
只有在别无选择时才应该使用全局变量。在90%的情况下,引入全局变量是为了节省传递参数的成本。然后发生多线程/单元测试/维护编码,你就有问题了。
是的,在90%的情况下全局变量是不好的。在你的大学生活中,不太可能遇到例外。我能想到的一个例外是处理固有的全局对象,比如中断表。像DB连接这样的东西似乎是全局的,但不是。
在多线程应用程序中,使用局部变量代替全局变量以避免竞态条件。
当多个线程访问共享资源时,至少有一个线程对数据有写访问权,就会发生竞争条件。然后,程序的结果是不可预测的,它取决于不同线程访问数据的顺序。
更多信息请访问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技术还可以封装全局变量,使其成为一种恰巧是全局变量的包或组件。通过使用这种组件,可以更容易地管理影响全局和使用全局功能的更改。
然而,尽管命名空间或结构技术可以帮助管理名称冲突,但使用全局变量(尤其是在现代多线程应用程序中)所带来的组件间耦合的潜在问题仍然存在。