我发现将全局变量视为一种特殊空间,存在于C程序正常函数层次结构之外,可以帮助理解。如果用每个函数的方框来绘制图表,并在方框之间连线显示程序执行过程中哪个函数调用了哪些其他函数,那么
main()
将位于顶部(因为它没有调用者),而所有其他函数都会出现在
main()
下面的某个层次上,与其它函数相连。
大多数数据仅存在于一个函数内——即在图表中的单个方框内。有些数据则从一个函数传递到另一个函数:大多数参数和返回值在像C这样的语言中都属于此类。但是全局变量则位于“所有方框之外”——任何函数都可以看到并更改它们,这种“开放性”使它们非常危险——如果任何函数中的任何代码都可以更改它们,那么对于您或对于在同一代码上工作的其他程序员来说,一旦程序变得真正庞大,就很难跟踪可能更改全局数据的所有可能位置。(这是编程语言普遍面临的“可变状态”问题,不仅仅局限于C语言,面向对象和函数式编程范式也在一定程度上解决了这个问题。)
在您的示例中,仅仅是因为您在问问题,
如果我想修改函数中的值并将其带回主函数,哪种方法更好?
这是一个线索,表明特定的值不应存储在全局变量中。您已经将此特定数据片段构想为仅在 main()
和 example()
两个函数之间共享的内容。根据我上面给出的推理,这意味着如果可能的话,变量应作为参数传递给 example()
,然后通过 example()
结尾处的 return
返回到 main()
。在 C 中,将指向 a
的指针传递到 example()
,然后在 example()
中修改 a
,以便在控制返回调用者后改变 a
,这是一种完全普通的习惯用法。但需要仔细记录哪些参数会以这种方式进行修改,否则您很快就会陷入与全局数据类似但不那么糟糕的情况,难以跟踪 a
可能发生的变化及其变化方式。
这并不是说全局变量都是坏的。它们存在有其原因。如果你的代码中许多部分需要对同一数据进行读/写访问,并且效率很重要,那么全局变量可能是实现这一点的最佳方式。在当今C语言运行最频繁的环境中——"接近硬件"的嵌入式系统或驱动程序代码中,通常会有硬件资源(如寄存器或专用内存),可以通过大量的全局变量最有效地访问。或者在某些程序中,您可能需要跟踪很多状态——一整套变量的值会影响整个程序的行为——传递这些值不仅效率低下,而且使程序
不清晰,因为您必须将相同的一组参数传递给大量的函数。(这的一个经典例子是游戏,其中游戏世界的当前状态、玩家位置、生命数等与大多数代码相关。)即使在这些情况下,关键是要很好地记录和命名全局变量,以便它们不会与其他类似命名的本地变量或函数参数发生冲突。
如果您想了解更高级但相关的主题,请参阅this answer进行简要说明,或this page进行更长时间的讨论,了解如何使用static
关键字将C语言中全局变量的范围(即可见性)限制为单个源文件,或在多个文件之间共享。这样可以更精细地控制全局数据的可访问性,并有助于缓解我上面提到的一些关于自由使用全局变量的问题。
example()
函数没有返回值,这样会更好。 - Iharob Al Asimistruct
聚合体。 - Basile Starynkevitchint
的函数缺少了return
。不要这样做!(如果没有return
,返回类型应该是void
)但如果你从未使用返回值,则返回类型应该是void
。 - Jonathan Leffler