我正在C中构建一个minishell,并且已经出现了一个障碍,似乎可以通过使用全局变量(确切地说是3)来轻松修复它。我认为全局变量是必要的原因是,替代方案是将这些变量传递给程序中的几乎每个函数。
变量是mainargc,mainargv和shiftedMArgV。前两个是参数的数量,并且参数列表分别传递给main。变量shiftMrgV是参数列表,但它可能已被移位。我正在尝试创建内置函数shift和unshift,并将shiftMArgV指向不同的参数。
那么,让这些全球变得愚蠢是不是很愚蠢?否则我将不得不修改大量的代码,而且我不确定我是否会因为它们的全局性而失去任何东西。
如果我确实将它们设为全局,那么从主头文件中这样做是不是很愚蠢?
感谢帮助人员,如果您需要任何澄清,请询问。
答案 0 :(得分:5)
作为全局变量的替代方案,请考虑全局函数':
extern int msh_mainArgC(void);
extern char **msh_mainArgV(void);
extern char **msh_shiftedArgV(void);
这些功能的实现很简单,但它允许您控制对内存的访问。如果你需要做一些奇特的事情,你可以改变功能的实现。 (我选择大写C和V以使差异更明显;当只有8-12字母名称的最后一个字符不同时,更难发现差异。)
这是一个定义这些功能的实现文件。在该文件中,存在存储相关信息的静态变量,以及用于设置和操纵变量的函数。原则上,如果你打了足够的const
限定符,你可以确保调用代码不能修改数据,除非通过设计这样做的函数(或通过使用强制转换去除常量)。
这对你来说是否值得讨论是值得商榷的。但它可能是。它是一个更接近面向对象的'经营方式。它是一种考虑然后丢弃的替代方案,而不是不考虑的东西。
请注意,使用这些函数的子系统可能有一个收集全局值的函数,然后将这些函数传递给它的从属函数。这使得下属不必知道值的来源;只是正确地操作它们。如果存在全局变量,则必须担心别名 - 是函数传递的值(全局变量的副本),但它是否也访问全局变量。有了这些功能,您不必以同样的方式担心这一点。
答案 1 :(得分:2)
我会说这不是愚蠢的,但你应该谨慎行事。
通常避免使用全局变量的原因并不是它们永远不会被使用,而是它们的使用导致人们经常让程序员崩溃和焚烧。通过经验,我们可以了解正确时间和错误时间之间的区别。
如果您已经深入思考问题,那么您正在尝试解决并考虑您为解决此问题而编写的代码,并考虑了此代码的未来(即您是否会影响可维护性)并且认为全局要么是不可避免的,要么更好地代表编码解决方案,那么你应该选择全局。
稍后,您可能会崩溃并烧毁,但这种体验将帮助您稍后辨别出更好的选择。相反,如果你觉得不使用全局变量可能导致崩溃和烧伤,那么这是你之前的经验,说你应该使用它们。你应该相信这种直觉。
Dijkstra a paper讨论goto
陈述可能造成的伤害,但在我看来,他的讨论也解释了我们对全局变量的一些困难。值得一读。
This answer和this answer也可能有用。
答案 2 :(得分:1)
只要它们以合乎逻辑的方式真正是全局变量,全局变量就可以了,而不仅仅是让你的生活更轻松的意思。例如,全局变量可以描述程序执行的环境,换句话说,可以描述与应用程序的系统级相关的属性。
答案 3 :(得分:1)
我曾经使用的所有复杂软件都有一组定义良好的全局变量。这没什么不对。它们的范围从少数几个到十几个。在后一种情况下,它们通常在逻辑上按结构分组。
Globals通常作为externs暴露在头文件中,然后在源文件中定义。请记住,全局变量在线程之间共享,因此必须受到保护,除非使用线程本地存储声明它们更有意义。
答案 4 :(得分:1)
对于shell,你有比这更多的状态。您具有重新映射的文件描述符的状态(由于各种原因需要跟踪),trap
处置,set
选项,环境和shell变量,...
通常,全局变量是错误的解决方案。相反,所有状态都应该保存在某种类型的上下文结构中,指向它的指针到处传递。这是一个很好的程序设计,通常它允许你在同一个进程中运行相同代码的多个实例(例如多个解释器,多个视频解码器等)。
话虽如此,shell是一个非常特殊的情况,因为它还处理很多的全局状态,你不能保留在一个结构中:信号配置,文件描述符和映射,子流程,进程组,控制终端等。有可能通过一个额外的层抽象出很多这样的内容,这样你就可以模拟所需的行为,同时保持在一个进程中可能存在多重性的干净上下文,但这样做很多比编写传统shell更困难的任务。因此,我可能会给自己一些余地,使用全局变量来编写shell“懒惰的方式”。但是,如果这是一个学习练习,请尝试在每次引入全局变量或状态时仔细识别,为什么要这样做,以及如何在没有全局状态的情况下以不同方式实现程序。这对你将来非常有用。