在C/ c++中,全局变量像我的教授认为的那样糟糕吗?
当前回答
我认为你的教授试图在一个坏习惯开始之前就阻止它。
全局变量有自己的位置,就像许多人说的,知道在哪里和何时使用它们可能很复杂。所以我认为与其深入研究全局变量的原因,方式,时间和地点教授决定禁止。谁知道呢,将来他可能会取消禁令。
其他回答
全局变量有多糟糕就有多糟糕。
如果您正在创建一个完全封装的程序,则可以使用全局变量。使用全局变量是一种“罪过”,但编程的罪过在很大程度上是哲学上的。
如果你看看洛杉矶。你会看到一种语言,它的变量是全局的。它是不可伸缩的,因为所有的库都只能使用全局变量。
也就是说,如果您有选择,并且可以忽略程序员的哲学,那么全局变量并不是那么糟糕。
Gotos也是,如果你使用得当的话。
最大的“坏”问题是,如果你使用错误,人们尖叫,火星着陆器坠毁,世界爆炸....或者类似的东西。
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技术还可以封装全局变量,使其成为一种恰巧是全局变量的包或组件。通过使用这种组件,可以更容易地管理影响全局和使用全局功能的更改。
然而,尽管命名空间或结构技术可以帮助管理名称冲突,但使用全局变量(尤其是在现代多线程应用程序中)所带来的组件间耦合的潜在问题仍然存在。
在企业内的web应用程序中,可以用于在服务器上保存会话/窗口/线程/用户特定的数据,以优化和保存连接不稳定时的工作损失。如前所述,需要处理竞争条件。我们使用类的单个实例来获取这些信息,并且对其进行了仔细的管理。
不,他们一点都不坏。你需要查看编译器生成的(机器)代码来做出判断,有时使用局部变量比使用全局变量要糟糕得多。还要注意,在局部变量上添加“static”基本上是使其成为全局变量(并产生真正的全局变量可以解决的其他丑陋问题)。“局部全局变量”尤其糟糕。
全局变量还可以让你完全控制内存的使用,这在局部变量中要困难得多。如今,这只在内存相当有限的嵌入式环境中才重要。在假定嵌入式环境与其他环境相同并假定编程规则全面相同之前,需要了解一些事情。
It is good that you question the rules being taught, most of them are not for the reasons you are being told. The most important lesson though is not that this is a rule to carry with you forever, but this is a rule required to honor in order to pass this class and move forward. In life you will find that for company XYZ you will have other programming rules that you in the end will have to honor in order to keep getting a paycheck. In both situations you can argue the rule, but I think you will have far better luck at a job than at school. You are just another of many students, your seat will be replaced soon, the professors wont, at a job you are one of a small team of players that have to see this product to the end and in that environment the rules developed are for the benefit of the team members as well as the product and the company, so if everyone is like minded or if for the particular product there is good engineering reason to violate something you learned in college or some book on generic programming, then sell your idea to the team and write it down as a valid if not the preferred method. Everything is fair game in the real world.
如果你遵循学校或书本上教给你的所有编程规则,那么你的编程生涯将非常有限。你很可能会生存下来,并拥有一个富有成效的事业,但你所能获得的环境的广度和宽度将是极其有限的。如果你知道规则是如何存在的,为什么会存在,并且能够捍卫它,那很好,如果你的理由只是“因为我的老师这么说”,那就不太好了。
请注意,这样的话题经常在工作场所被争论,并且将继续存在,随着编译器和处理器(以及语言)的发展,这些类型的规则也在发展,如果不捍卫你的立场,可能会被持不同意见的人教训一课,你就不会前进。
与此同时,那个说话声音最大或拿着最大棍子的人说什么,你就做什么(直到你是那个喊得最大、拿着最大棍子的人)。
全局变量通常很糟糕,特别是当其他人正在处理相同的代码,并且不想花20分钟搜索变量被引用的所有位置时。添加修改变量的线程带来了一个全新的问题。
在单个翻译单元中使用匿名名称空间中的全局常量是很好的,在专业应用程序和库中无处不在。但是如果数据是可变的,并且/或者它必须在多个tu之间共享,那么您可能想要封装它——如果不是为了设计,那么也是为了任何人调试或使用您的代码。
推荐文章
- 如何构建和使用谷歌TensorFlow c++ api
- C“int”的大小是2字节还是4字节?
- 多维数组如何在内存中格式化?
- printf()和puts()在C语言中的区别是什么?
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 有效,但毫无价值的语法在开关情况下?
- 如何为Fedora安装g++ ?
- Std::cin输入空格?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- 有一个好的Valgrind Windows的替代品吗?
- gcc在哪里查找C和c++头文件?
- 为什么我们需要require require ?