全局variables是不好的?

在C / C ++中,全局variables和我的教授认为的一样糟糕吗?

全局variables的问题在于,由于每个函数都可以访问这些variables,所以越来越难以找出哪些函数实际读写这些variables。

要了解应用程序的工作原理,几乎必须考虑修改全局状态的每个函数。 这是可以做到的,但随着应用程序的增长,将变得越来越难以实现(或者至less是完全浪费时间)。

如果不依赖全局variables,则可以根据需要在不同的函数之间传递状态。 这样你就可以更好地理解每个函数的function,因为你不需要考虑全局状态。

我的教授曾经这样说过:如果使用正确的话,使用全局variables是可以的。 我认为我没有正确地使用它们,所以我很less使用它们。

重要的是要记住总体目标:清晰度

“无全局variables”规则是因为大多数时候,全局variables使得代码的含义变得不那么清晰。

但是,像许多规则一样,人们记住规则,而不是规则打算做什么。

我已经看到了通过传递大量参数来增加代码大小的程序,只是为了避免全局variables的恶意。 最后,使用全局variables会使程序更清晰 。 通过不顾一切地遵守规则的话,原来的程序员失败了这个规则的意图。

所以,是的,全球通常是不好的。 但是如果你最终感觉到程序员的意图是通过使用全局variables来变得更加清晰的话,那就继续吧。 但是,请记住当您强制某人访问第二部分代码(全局variables)时,自动发生的清晰度下降,以了解第一部分的工作原理。

全局variables只能在没有其他select的情况下使用。 是的,那包括单身人士。 在90%的时间里,引入全局variables来节省传递参数的成本。 然后multithreading/unit testing/维护编码发生,并且您有问题。

所以是的,在90%的情况下,全局variables是不好的。 在你大学的时候,你是不可能看到例外的。 我能想到的一个例外是处理固有的全局对象,例如中断表。 像DB连接似乎是全球性的,但不是。

是的,但是,如果不停止使用全局variables的代码并开始编写使用全局variables的代码的其他代码,则不会产生全局variables的成本。 但成本仍然存在。

换句话说,这是一个长期的间接成本,因此大多数人认为这并不坏。

我会用另外一个问题来回答这个问题:你使用singeltons还是singeltons不好?

因为(几乎所有)singelton用法是一个荣耀的全球variables。

如果在最高法院审判期间,您的代码可能会被深入审查 ,那么您要确保避免全局variables。

看到这篇文章: 越野车呼吸测醉器代码反映了来源审查的重要性

这两个研究所确定的代码风格存在一些问题。 与审稿人有关的文体问题之一是大量使用无保护的全局variables 。 这被认为是不好的forms,因为它增加了程序状态变得不一致的风险,或者这些值会被无意地修改或覆盖。 研究人员还对整个代码中的小数精度没有保持一致表示担忧。

男人,我敢打赌,开发人员希望他们没有使用全局variables!

全局variables和你所做的一样糟糕,不能less。

如果你正在创build一个完全封装的程序,你可以使用全局variables。 使用全局variables是一个“罪”,但是编程的罪恶是非常哲学的。

如果你检查L.in.oleum ,你会看到一个语言variables是全球性的。 它是不可缩放的,因为库只能使用全局variables。

也就是说,如果你有select,而且可以忽略程序员哲学,全局variables并不是那么糟糕。

如果你正确地使用它们,Gotos也不是。

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

全局variables为程序员创build的问题是它扩展了使用全局variables的各个组件之间的组件间耦合表面。 这意味着,随着使用全局variables的组件数量的增加,交互的复杂性也会增加。 这种增加的耦合通常会使修改时更容易将缺陷注入系统,并使缺陷更难以诊断和纠正。 这种增加耦合还可以减less可用选项的数量,从而可以增加更改所需的工作量,因为通常必须跟踪也使用全局variables的各个模块,以便确定更改的后果。

封装的目的,与使用全局variables基本上是相反的,是为了使理解和改变源更容易,更安全,更容易testing,减less耦合。 不使用全局variables时,使用unit testing要容易得多。

例如,如果您有一个简单的全局整型variables用作枚举指示器,并将各个组件用作状态机,然后通过为新组件添加新状态来进行更改,则必须跟踪其他所有其他组件组件来确保更改不会影响到它们。 一个可能出现的问题的例子是,如果一个switch语句用于testing每个当前值的case语句的枚举全局variables的值在不同的地方被使用,那么碰巧一些switch语句没有default情况下,处理一个意外的价值的全球突然你有未定义的行为至于应用程序而言。

另一方面,共享数据区域的使用可能被用来包含整个应用程序引用的一组全局参数。 这种方法通常用于内存占用量小的embedded式应用程序。

当在这些types的应用程序中使用全局variables时,通常将写入数据区的责任分配给单个组件,而所有其他组件将该区域视为const并从中读取,而不写入。 采取这种方法限制了可能发展的问题。

这里有一些使用全局variables需要解决的问题。

当一个全局variables(比如一个struct)的源被修改时,所有使用它的东西都必须重新编译,这样所有使用该variables的东西都知道它的真实大小和内存模板。

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

debugging使用全局variables的multithreading应用程序可能会更困难。 您可能会遇到可能产生难以复制的缺陷的竞争条件 。 有几个组件通过一个全局variables进行通信,特别是在一个multithreading应用程序中,能够知道什么组件正在改变variables的时间和方式,是非常难以理解的。

名称冲突可能是使用全局variables的问题。 与全局variables名称相同的局部variables可以隐藏全局variables。 使用C编程语言时,您还遇到了命名约定问题。 解决方法是将系统分成具有全部variables的子系统,全部variables都以相同的前三个字母开始(参见解决名称C中的名称空间冲突 )。 C ++提供了命名空间,使用C语言可以通过创build一个全局可见的结构体来解决这个问题,它的成员是各种数据项和指向数据和函数的指针,这些数据和函数在文件中被提供为静态的,因此只有文件可见性,全局可见的结构。

在某些情况下,原来的应用程序意图被更改,以便为单个线程提供状态的全局variables被修改,以允许运行多个重复的线程。 一个例子就是为单个用户devise一个简单的应用程序,使用全局variables来处理状态,然后从pipe理请求中添加一个REST接口,以允许远程应用程序充当虚拟用户。 所以现在你需要复制全局variables及其状态信息,这样单个用户以及来自远程应用程序的每个虚拟用户都拥有自己独特的全局variables集合。

正如有人在另一条线上所说的(我是释义)“这样的规则不应该被打破,直到你完全明白这样做的后果。

有些时候全局variables是必要的,或者至less非常有用(例如使用系统定义的callback)。 另一方面,他们也因为你被告知的所有原因而非常危险。

编程有很多方面可能应该留给专家。 有时你需要一把非常锋利的刀。 但是,直到你准备好了,你才能使用它。

全局variables通常是不好的,特别是如果其他人正在使用相同的代码,并且不想花费20分钟searchvariables被引用的所有地方。 而添加修改variables的线程会带来全新的令人头痛的问题。

在单个翻译单元中使用的匿名命名空间中的全局常量在专业应用程序和库中很好,无处不在。 但是,如果数据是可变的,并且/或者它必须在多个TU之间共享,则可能需要封装它 – 如果不是为了devise的缘故,那么为了任何人debugging或使用您的代码。

绝对不。 滥用他们虽然…这是不好的。

毫不留情地去除它们就是这样……毫无意义的。 除非你知道自己的优势和劣势,否则最好是按照你的教导学习来清楚指导,但是全局variables并没有什么明显的错误。 当你了解利弊时更好地做出自己的决定。

全局variables是不好的,如果它们允许你操作应该只在本地修改的程序的各个方面。 在OOP中,全局variables经常与封装思想相冲突。

我想你的教授正试图阻止坏习惯,甚至开始。

全球variables有其自己的位置,就像很多人说,知道何时何地使用它们可能是复杂的。 所以我认为,不要深入了解教授决定禁止的全球variables的原因,方式,时间和地点。 谁知道,他可能会在未来取消他们。

使用全局variables有点像扫地毯下的污垢。 这是一个快速的解决scheme,在短期内比用尘盘或真空清理起来容易得多。 但是,如果你以后最后搬到地毯,你会在下面有一个惊喜的混乱。

问题不在于他们不好 ,而在于他们更危险 。 他们有自己的优点和缺点,有些情况下,他们要么是最有效的,要么是唯一的方法来完成一个特定的任务。 但是,即使您采取措施始终正确使用它们,也容易被误用。

一些优点:

  • 可以从任何function访问。
  • 可以从多个线程访问。
  • 在程序结束之前永远不会超出范围。

一些缺点:

  • 可以从任何函数访问,而不需要显式拖入参数和/或文档。
  • 不是线程安全的。
  • 污染全局名称空间并可能导致名称冲突,除非采取措施来防止这种情况。

请注意,如果你愿意的话,我列出的前两个利弊和前两个利弊是完全一样的,只是用不同的措词。 这是因为全局variables的特征确实是有用的,但是使它们有用的特征是所有问题的根源。

一些潜在的解决scheme的一些问题:

  • 考虑他们是否真的是问题的最佳或最有效的解决scheme。 如果有更好的解决scheme,请使用它。
  • 把它们放在一个具有唯一名称的命名空间[C ++]或单例结构体[C,C ++]中(一个好的例子是GlobalsGlobalVars ),或者对全局variables使用标准化的命名约定(比如global_[name]或者g_module_varNameStyle如评论中的underscore_d所述))。 这将同时logging它们的使用(可以通过search名称空间/结构名称来查找使用全局variables的代码),并将对全局名称空间的影响降至最低。
  • 对于访问全局variables的任何函数,明确地logging它读取哪些variables以及写入哪些variables。 这将使故障排除更容易。
  • 把它们放在它们自己的源文件中,并在关联的头文件中声明它们是extern的,所以它们的使用可以限制到需要访问它们的编译单元。 如果你的代码依赖于很多全局variables,但是每个编译单元只需要访问其中的一小部分,就可以考虑将它们sorting为多个源文件,所以限制每个文件对全局variables的访问就更容易了。
  • 设置一个机制来locking和解锁它们,和/或devise你的代码,以便尽可能less的function需要实际修改全局variables。 读取它们比编写它们要安全得多,尽pipe线程竞争在multithreading程序中可能仍然存在问题。
  • 基本上,尽量减less对他们的访问,并最大限度地提高名称的独特 你想避免名称冲突,并尽可能less的function,可能会修改任何给定的variables。

无论好坏取决于你如何使用它们。 大多数人倾向于使用他们,因此一般对他们很谨慎。 如果使用得当,他们可以成为一大福音。 如果使用不好,但是,他们可以,并回来咬你什么时候,以及你最不期待的。

看看它的一个好方法就是它们本身并不坏,但是它们使得糟糕的devise成为可能,并且可能成倍增加不良devise的影响。


即使你不打算使用它们,最好是知道如何安全地使用它们,而不是select不使用它们,因为你不知道如何安全地使用它们。 如果您发现自己处于需要维护依赖全局variables的预先存在的代码的情况,那么如果您不知道如何正确使用它们,则可能会遇到困难。

全局variables在小程序中是好的,但是如果在大的程序中使用相同的方式,那么可怕的是很糟糕

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

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

不,他们一点都不坏。 您需要查看编译器生成的(机器)代码来做出这个决定,有时使用本地比全局更糟糕。 另外请注意,将“静态”放在局部variables上基本上使其成为一个全局的variables(并创build了一个真正的全局可以解决的其他难题)。 “本地全球”特别糟糕。

Globals也可以让你清楚地控制你的内存使用情况,这对于本地人来说是一个更难的事情。 这些日子只对内存非常有限的embedded式环境很重要。 在您假设embedded式和其他环境相同之前需要知道的东西,并且假设所有的编程规则都是相同的。

你对所教授的规则提出质疑是很好的,其中大部分不是出于你被告知的原因。 然而,最重要的一个教训并不是这是一个永远随身携带的规则,但这是为了通过这个class级而向前迈进所需要遵守的规则。 在生活中,你会发现,对于XYZ公司,你将有其他的编程规则,你最终将不得不兑现以保持薪水。 在这两种情况下,你可以争论这个规则,但是我认为你在工作上运气比在学校要好得多。 你只是许多学生中的另一个,你的座位很快就会被replace掉,教授们会这样做,在一个工作中,你是一个必须看到这个产品的小团队中的一员,在那个环境中,所以如果每个人都像头脑一样,或者如果对于特定的产品,有很好的工程理由来违反你在大学里学到的东西或者一些关于generics编程的书,那么把你的想法卖给该团队把它写下来作为一个有效的,如果不是首选的方法。 在现实世界中,一切都是公平的游戏。

如果你遵循在学校或书本上教给你的所有编程规则,你的编程生涯将是非常有限的。 你可能会生存下来,拥有丰硕的职业生涯,但是可用的环境的广度和宽度将非常有限。 如果你知道规则如何以及为什么可以保护它,那么这很好,如果你唯一的理由是“因为我的老师这样说”,那么那不是那么好。

请注意,这样的话题经常在工作场所中被讨论,而且随着编译器和处理器(以及语言)的发展,这些types的规则也将继续存在,并且没有捍卫自己的立场,并且可能被某个人用另一个意见前进。

同时,只要做最大声最大的那个,或者最大的一根棍子就说(直到你喊的最响的那个时候,拿着最大的那根棍子)。

是的,因为如果你让不称职的程序员使用它们(阅读90%,尤其是科学家),你最终会得到超过20个文件的600多个全局variables和一个12000行的项目,其中80%的函数使用void,返回void和完全基于全球状态。

除非你知道整个项目,否则很快就不可能知道在任何一点上发生了什么。

全局variables的使用实际上取决于需求。 它的好处是,它减less了重复传递值的开销。

但是你的教授是对的,因为它提出了安全问题,所以尽可能地避免使用全局variables。 全局variables也会产生有时难以debugging的问题

例如:-

variables值在运行时得到修改的情况。 在那个时候,很难确定代码的哪一部分正在修改它,以及在什么条件下。

我想在这个主题上反驳这个问题,即它使multithreading本身更难或不可能。 全局variables是共享状态,但全局variables(例如传递指针)也可能共享状态。 multithreading的问题是如何正确地使用共享状态,而不是这个状态是否恰好通过全局variables或其他东西共享。

大多数情况下,当你进行multithreading时,你需要分享一些东西。 例如,在生产者 – 消费者模式中,您可能会共享一些包含工作单元的线程安全队列。 而且你可以分享它,因为这个数据结构是线程安全的。 当涉及到线程安全性时,该队列是否全局是完全不相关的。

在这个线程中expression的隐含的希望是,当不使用全局variables的时候,将程序从单线程转换到multithreading会更容易。 是的,全局变得更容易拍摄自己的脚,但有很多方法可以拍摄自己。

我并不主张全局variables,因为其他的观点依然存在,我的观点只不过是程序中的线程数与variables范围无关。

迟早你将需要改变这个variables的设置,或者访问它时会发生什么,或者你只需​​要查找它被改变的地方。

没有全局variables实际上总是更好。 只要写下大坝得到并设置方法,当你需要他们一天,一周或一个月之后,你就可以收到你。

我通常使用全局variables很less改变的值,像dynamic加载库中的函数单向函数或函数指针。 在multithreading应用程序中使用可变全局variables往往会导致很难跟踪错误,所以我尽量避免这种情况。

使用全局而不是传递参数通常会更快,但是如果您正在编写一个multithreading应用程序(现在经常这样做),它通常不能很好地工作(您可以使用线程静态方法,但是性能增益值得怀疑) 。

在一天结束的时候,你的程序或应用程序仍然可以工作,但它是一个整洁和完整的理解正在发生的事情。 如果在所有函数中共享一个variables值,那么跟踪哪个函数正在改变值(如果函数是这样的话)并且使得debugging百万次更困难

configuration方面, Global很好。 当我们希望我们的configuration/更改整个项目 产生全球影响时。

因此,我们可以更改一个configuration ,并将更改指向整个项目 。 但是我必须警告你必须非常聪明地使用全局variables。

安全性更低意味着任何人都可以操纵这些variables,如果它们被声明为全局的,为了解释这个例子,如果你的银行程序中有一个全局variables,用户函数可以操作这个以及银行职员也可以操纵this so there is a problem .only user should be given the read only and withdraw function but the clerk of the bank can add the amount when the user personally gives the cash in the desk.this is the way it works

In web applications within an enterprize can be used for holding session/window/thread/user specific data on the server for reasons of optimization and to preserve against loss of work where connection are unstable. As mentioned, race conditions need to be handled. We use a single instance of a class for this information and it is carefully managed.

In a multi-threaded application, use local variables in place of global variables to avoid a race condition.

A race condition occurs when multiple thread access a shared resource, with at least one thread having a write access to the data. Then, the result of the program is not predictable, and depends on the order of accesses to the data by different threads.

More on this here, https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code