全局变量不好吗?

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

160588 次浏览

是的,但是在停止使用全局变量的代码并开始编写使用全局变量的代码之前,您不会招致全局变量的成本。但成本依然存在。

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

全局变量是不好的,如果它们允许您操作应该只在本地修改的程序的某些方面。在面向对象编程中,全局变量经常与封装思想相冲突。

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

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

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

如果你检出L.in.oleum,你会看到一种语言,它的变量是完全全局的。它是不可伸缩的,因为所有的库都只能使用全局变量。

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

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

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

我将用另一个问题来回答这个问题:你使用singeltons/ singeltons不好吗?

因为(几乎所有)单变量的使用都是一个美化的全局变量。

我认为你的教授试图在一个坏习惯开始之前就阻止它。

全局变量有自己的位置,就像许多人说的,知道在哪里和何时使用它们可能很复杂。所以我认为与其深入研究全局变量的原因,方式,时间和地点教授决定禁止。谁知道呢,将来他可能会取消禁令。

全局变量通常很糟糕,特别是当其他人正在处理相同的代码,并且不想花20分钟搜索变量被引用的所有位置时。添加修改变量的线程带来了一个全新的问题。

在单个翻译单元中使用匿名名称空间中的全局常量是很好的,在专业应用程序和库中无处不在。但是如果数据是可变的,并且/或者它必须在多个tu之间共享,那么您可能想要封装它——如果不是为了设计,那么也是为了任何人调试或使用您的代码。

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

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

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

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

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

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

只有在别无选择时才应该使用全局变量。在90%的情况下,引入全局变量是为了节省传递参数的成本。然后发生多线程/单元测试/维护编码,你就有问题了。

是的,在90%的情况下全局变量是不好的。在你的大学生活中,不太可能遇到例外。我能想到的一个例外是处理固有的全局对象,比如中断表。像DB connection 似乎这样的东西是全局的,但不是。

正如有人在另一篇文章中所说的那样:“在你完全理解这样做的后果之前,不应该打破这样的规则。”

有时候,全局变量是必要的,或者至少是非常有用的(例如,处理系统定义的回调)。另一方面,他们也非常危险,因为所有你被告知的原因。

编程的许多方面可能应该留给专家去做。有时候你需要一把非常锋利的刀。但在你准备好之前,你不能使用它……

迟早,您将需要更改该变量的设置方式或访问它时发生的情况,或者您只需要查找它被更改的位置。

实际上,不使用全局变量总是更好。只需编写大坝获取和设置方法,并在一天、一周或一个月后当你需要它们时通知你。

使用全局变量有点像扫地毯下的灰尘。这是一种快速的解决方法,在短期内比用吸尘盆或吸尘器清理要容易得多。然而,如果你后来搬了地毯,下面会有一个大的惊喜。

不,他们一点都不坏。你需要查看编译器生成的(机器)代码来做出判断,有时使用局部变量比使用全局变量要糟糕得多。还要注意,在局部变量上添加“static”基本上是使其成为全局变量(并产生真正的全局变量可以解决的其他丑陋问题)。“局部全局变量”尤其糟糕。

全局变量还可以让你完全控制内存的使用,这在局部变量中要困难得多。如今,这只在内存相当有限的嵌入式环境中才重要。在假定嵌入式环境与其他环境相同并假定编程规则全面相同之前,需要了解一些事情。

你对所教的规则提出质疑是件好事,其中大多数不是因为你被告知的原因。但最重要的一课并不是说这是一个要永远遵循的规则,而是为了通过这门课并继续前进而必须遵守的规则。在生活中,你会发现,对于XYZ公司,你会有其他的编程规则,为了继续获得薪水,你最终必须遵守这些规则。在这两种情况下,你都可以对规则提出异议,但我认为你在工作中会比在学校中幸运得多。你只是另一个的学生,你的座位很快会被取代,教授不会,在工作,你是一个小团队的球员之一,看到这个产品,在这种环境下的规则开发团队成员的利益以及产品和公司,所以如果每个人都喜欢的或者特定产品有很好的工程理由违反一些你在学校所学的东西或一些关于泛型编程的书,然后把你的想法卖给团队,把它作为一个有效的(如果不是首选的)方法写下来。在现实世界中,一切都是公平的。

如果你遵循学校或书本上教给你的所有编程规则,那么你的编程生涯将非常有限。你很可能会生存下来,并拥有一个富有成效的事业,但你所能获得的环境的广度和宽度将是极其有限的。如果你知道规则是如何存在的,为什么会存在,并且能够捍卫它,那很好,如果你的理由只是“因为我的老师这么说”,那就不太好了。

请注意,这样的话题经常在工作场所被争论,并且将继续存在,随着编译器和处理器(以及语言)的发展,这些类型的规则也在发展,如果不捍卫你的立场,可能会被持不同意见的人教训一课,你就不会前进。

与此同时,那个说话声音最大或拿着最大棍子的人说什么,你就做什么(直到你是那个喊得最大、拿着最大棍子的人)。

绝对不是。但是滥用它们……这很糟糕。

出于某种原因而无意识地删除它们只是……盲目的。除非您知道其优点和缺点,否则最好避免使用全局变量,并按照您学到的方法进行操作,但全局变量并没有什么隐含的错误。当你了解了利弊后,最好自己做决定。

如果在最高法院审判中,你的代码可能会在密集的审查下结束,那么你要确保避免使用全局变量。

参见这篇文章: 漏洞百出的呼气测试仪代码反映了源代码审查的重要性

有一些问题与 所识别的代码的样式 两项研究都证明了这一点。一个是文体 审稿人关心的问题 的广泛使用是否没有保护措施 全局变量< / em >。这被认为是 糟糕的形式是因为它增加了 程序状态会有风险 变得不一致或价值观 会无意中被修改还是 覆盖。研究人员还 表达了对事实的担忧 而十进制精度则不是 在整个 代码。< / p >

伙计,我敢打赌那些开发人员希望他们没有使用全局变量!

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

“无全局变量”规则的存在是因为大多数时候,全局变量使代码的含义不太清楚。

然而,像许多规则一样,人们记住的是规则,而不是规则的意图。

我曾经见过一些程序,为了避免全局变量的危害,通过传递大量参数,使代码的大小增加了一倍。最后,使用全局变量将使程序对读取它的人来说是更清晰的。由于盲目地遵守规则的文字,原来的程序员未能实现规则的意图。

所以,是的,全局变量通常不好。但是如果你觉得在最后,程序员的意图通过使用全局变量变得更加清晰,那么就继续吧。但是,请记住,当您强迫某人访问第二段代码(全局代码)以理解第一部分是如何工作的时,清晰度会自动下降。

我通常对很少改变的值使用全局变量,如单例或动态加载库中函数的函数指针。在多线程应用程序中使用可变全局变量往往会导致难以跟踪错误,所以我尽量避免将其作为通用规则。

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

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

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

安全并不意味着任何一个可以操纵变量声明的全局,为这一解释这个例子中如果你有平衡作为一个全局变量在你们银行程序用户函数可以操纵以及银行职员也可以操纵这这是一个问题只有用户应该考虑到只读和退出函数,而是银行的职员可以添加量当用户亲自给的现金在桌子上。这就是它的运作方式

全局变量的使用实际上取决于需求。它的优点是减少了重复传递值的开销。

但是你的教授是对的,因为它会引发安全问题,所以应该尽可能避免使用全局变量。全局变量也会产生问题,有时是调试困难. c。

例如:-

变量值在运行时上获得修改的情况。此时,很难确定是哪部分代码在什么条件下修改了它。

全局变量给程序员带来的问题是,它在使用全局变量的各个组件之间展开了组件间耦合面。这意味着,随着使用全局变量的组件数量的增加,交互的复杂性也会增加。这种增加的耦合通常使缺陷在进行更改时更容易注入到系统中,也使缺陷更难诊断和纠正。在进行更改时,这种增加的耦合还可以减少可用选项的数量,并且可以增加更改所需的工作,因为通常必须跟踪也使用全局变量的各个模块,以确定更改的结果。

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

例如,如果您有一个简单的全局整型变量,它被用作各种组件用作状态机的枚举指示器,然后您通过为新组件添加新状态来进行更改,那么您必须跟踪所有其他组件,以确保更改不会影响它们。一个可能的问题的例子是,如果一个switch语句用于测试枚举全局变量的值,其中每个当前值都有case语句被用于不同的地方,而恰巧一些switch语句没有default情况来处理全局的意外值,那么就应用程序而言,突然之间你就有了未定义的行为。

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

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

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

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

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

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

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

在某些情况下,原始应用程序的意图被更改,以便修改为单个线程提供状态的全局变量,以允许多个重复的线程运行。例如,一个简单的应用程序为单个用户设计,使用全局变量作为状态,然后从管理层请求添加REST接口以允许远程应用程序充当虚拟用户。因此,现在必须复制全局变量及其状态信息,以便单个用户以及来自远程应用程序的每个虚拟用户都拥有自己的惟一全局变量集。

使用c++ namespace和C的struct技术

对于c++编程语言,namespace指令在减少名称冲突的机会方面有很大的帮助。namespaceclass以及各种访问关键字(privateprotectedpublic)提供了封装变量所需的大部分工具。然而,C编程语言并没有提供这个指令。这个stackoverflow帖子C语言命名空间提供了一些C语言的技巧。

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

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

然而,虽然namespacestruct技术可以帮助管理名称冲突,但使用全局变量引入的组件间耦合的潜在问题仍然存在,特别是在现代多线程应用程序中。

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

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

更多关于这个的信息,https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code

问题不在于它们是,而在于它们是危险的。他们有自己的优点和缺点,在某些情况下,他们要么是最有效的,要么是完成特定任务的唯一方法。然而,它们很容易被误用,即使你采取措施总是正确地使用它们。

一些优点:

  • 可以从任何函数访问。
  • 可以从多个线程访问。
  • 在项目结束前都不会超出范围。

一些缺点:

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

请注意,如果你愿意的话,我列出的前两个优点和前两个缺点是完全相同的事情,只是措辞不同。这是因为全局变量的特性确实是有用的,但使它们有用的特性正是它们所有问题的根源。

一些问题的潜在解决方案:

  • 考虑一下它们是否是问题的最佳或最有效的解决方案。如果有任何更好的解决方案,使用它代替。
  • 将它们放在命名空间[c++]或具有唯一名称的单例结构体[C, c++]中(一个很好的例子是GlobalsGlobalVars),或使用全局变量的标准化命名约定(如global_[name]g_module_varNameStyle(如注释中的underscore_d所述))。这将记录它们的使用(您可以通过搜索名称空间/结构名称找到使用全局变量的代码),并将对全局名称空间的影响降至最低。
  • 对于任何访问全局变量的函数,都要显式地记录它读取和写入哪些变量。这将使故障排除更容易。
  • 将它们放在它们自己的源文件中,并在相关的头文件中声明它们extern,因此它们的使用可以限制在需要访问它们的编译单元中。如果您的代码依赖于大量全局变量,但每个编译单元只需要访问其中的少数几个,那么您可以考虑将它们排序到多个源文件中,这样就更容易限制每个文件对全局变量的访问。
  • 设置一种机制来锁定和解锁它们,和/或设计你的代码,以便尽可能少的函数需要真正修改全局变量。读取它们比写入它们要安全得多,尽管线程竞争仍然可能在多线程程序中引起问题。
  • 基本上,最小化对它们的访问,并最大化名称的唯一性。您希望避免名称冲突,并尽可能少地使用可能修改任何给定变量的函数。

它们是好是坏取决于你如何使用它们。大多数人倾向于不好地使用它们,因此对它们普遍持谨慎态度。如果使用得当,它们可以成为一大福音;然而,如果使用不当,它们会在你最意想不到的时候回来咬你一口。

从一个好的角度来看,它们本身并不坏,但它们导致了糟糕的设计,并且会成倍地增加糟糕设计的影响。


即使你不打算使用它们,知道如何安全使用它们并选择不使用,也比不使用它们因为你不知道如何安全使用它们要好。如果您发现自己处于需要维护依赖于全局变量的预先存在的代码的情况下,如果您不知道如何正确使用它们,那么您可能会遇到困难。

在一天结束时,你的程序或应用程序仍然可以工作,但这是一个整洁的问题,并对正在发生的事情有一个完整的理解。如果在所有函数之间共享一个变量值,那么可能很难跟踪是哪个函数更改了该值(如果函数更改了该值),这将使调试变得更加困难

我想要反驳这篇文章所提出的观点,即它使多线程更加困难或根本不可能。全局变量是共享状态,但全局变量的替代方法(例如传递指针)也可能共享状态。多线程的问题在于如何正确地使用共享状态,而不是该状态是否恰好通过全局变量或其他方式共享。

大多数情况下,当你执行多线程时,你需要共享一些东西。例如,在生产者-消费者模式中,您可以共享一些包含工作单元的线程安全队列。您可以共享它,因为该数据结构是线程安全的。当涉及到线程安全时,队列是否是全局的完全无关紧要。

在这个线程中隐含的希望是,在不使用全局变量的情况下,将程序从单线程转换为多线程会更容易,这是天真的。是的,全局变量让搬起石头砸自己的脚变得更容易,但搬起石头砸自己的方法有很多。

我并不提倡全局变量,因为其他观点仍然成立,我的观点仅仅是程序中的线程数与变量作用域无关。

在企业内的web应用程序中,可以用于在服务器上保存会话/窗口/线程/用户特定的数据,以优化和保存连接不稳定时的工作损失。如前所述,需要处理竞争条件。我们使用类的单个实例来获取这些信息,并且对其进行了仔细的管理。

当涉及到配置时,全球是很好的。当我们希望我们的< < em >配置/变化/ em >整个项目上有一个全球影响时。

因此,我们可以改变一个配置,并将变化定向到整个项目。但我必须警告你,你必须非常聪明地使用全局变量。