将全局变量传递给函数是否有问题?

考虑以下函数声明:

int abmeld(char *strsend) 

这就是这样称呼的

 abmeld(str); 

其中str是在程序文件的开头(在包含之后)声明和初始化的全局变量,如下所示:

 char str[300] = ""; 

现在我已经知道这是不必要的代码(你可以从任何函数中访问和修改char数组而不必传递它),但这实际上是否有问题呢?

是否存在可能因将已经全局范围的变量传递给函数而导致的后果(如硬错误可能性或未定义的行为)?

我会说相反,将全局传递给函数几乎从来没有问题(使用大量的全局变量通常很脏,代码变得不可读)。

与使用大量全局(甚至静态)变量的函数相比,轻微(或根本不)依赖于全局状态的函数通常更易读且更易理解。 在许多函数中更改的全局变量会使您的程序变得混乱。

(永远不要忘记,您不仅要为计算机编写代码,还要为您的同事编写代码 – 甚至可能在几个月内编写代码 – 谁将不得不改进您的源代码)

此外,使用全局状态的函数通常不可重入 。

最后, 未定义的行为主要与全局vs参数数据正交。 特别是, 缓冲区溢出既可以使用全局变量,也可以使用指向某个数组的指针(例如参数或某个局部变量)。

一个非常粗略的经验法则是避免用超过7项( 魔法数字7,+或 – 2 )加载开发人员的大脑; 因此民间传说规则要避免超过7个参数或超过7个全局变量。

有一种情况可能会出现问题:如果abmeld已经对str全局abmeld 。 作为一个简单的例子:

 extern char str[300]; void abmeld(const char *s) { snprintf(str, 300, "abmeld: %s\n", s); } 

然后abmeld(str)具有未定义的行为,因为当其目标缓冲区与其任何输入重叠时, snprintf具有未定义的行为。

这说明了全局变量很麻烦的原因之一:为了知道作为参数传递给abmeld的安全abmeld ,你不仅要知道它写入str (肯定会被记录),而是它如何做到 -它本来可以写的

 void abmeld(const char *s) { size_t n = strlen(s); size_t maxcopy = min(n, 300 - sizeof "abmeld: \n"); size_t after = maxcopy + sizeof "abmeld: " - 1; memmove(str + sizeof "abmeld: " - 1, s, maxcopy); memcpy(str, "abmeld: ", sizeof "abmeld: " - 1); str[after] = '\n'; str[after+1] = 0; } 

然后只要它是一个有效的C字符串,无论指向什么,它都会有明确定义的行为。

现在我已经知道这是不必要的代码(你可以从任何函数中访问和修改char数组而不必传递它),但这实际上是否有问题呢?

函数无论是接收本地变量还是全局定义的变量都无关紧要。 全局变量的问题有时与您可能不知道正在访问/更改其值的程序的哪些部分有关。 线程安全也可能相关。

将全局变量传递给函数非常非常常见。 例:

 const char* global = "Example"; void foo() { printf("%s\n", global ); } 

显然,这将全局传递给printf设计的C语言使这种用法安全。 很快就会出现一个错误的实现。

一点都不。

现在我已经知道这是不必要的代码

不总是。 在函数没有默认参数的情况下,您必须遵守函数原型并传递全局变量。 但是,该函数不关心指针是指向本地变量还是全局变量。

 /* main.c */ char str[300] = {0}; int abmeld(char *strsend) { /* Do something...process strsend */ return 0; } int main( void ) { abmeld(str); /*Cannot pass void here as abmeld expects a char* */ char localstr[10] = {0}; abmeld(localstr); return 0; } 

您想要将全局变量传递给函数。 您正在使用的函数很简单,需要参数,然后您必须传递函数中所需参数类型的参数。

这里,传递全局变量或局部变量没有任何问题或问题。 您必须处理要传递的参数的数据类型。

  1. abmeld(char *)方法只能修改/使用提供给它的参数。 虽然将全局变量传递给此方法可能不好,但这并不禁止任何人使用任何其他char *调用此方法。

    • 例如,如果此方法检查指向的字符串是否为回文,则编写此方法可以说明良好的编码。 现在,每当他/她想知道该字符串是否是回文时,任何人都可以调用它。
  2. 现在我已经知道这是不必要的代码(你可以从任何函数中访问和修改char数组而不必传递它),但这实际上是否有问题呢?

    • 如上所述,它可能不是不必要的代码。 编写新方法的目的是划分一项工作。 换句话说, 方法应该只做一件事。 除非已经编写了方法abmeld(char *)来专门修改那个特定的全局变量(甚至可能是一件好事),所以代码完全可以按照它的编写方式完成,只要它与提供给它的论据。

    • 有许多例子,这些代码可能存在问题,而且问题很直观。 例如,可能有更多方法可能正在修改/处理全局字符串。 但是,这些问题是使用全局变量时出现的问题。 要摆脱这些问题,你必须摆脱全局变量而不是方法,因为它与全局变量一起使用不是方法的错。

  3. 是否存在可能因将已经全局范围的变量传递给函数而导致的后果(如硬错误可能性或未定义的行为)?

    • 不能说这个权威,但我不知道。 没有读过任何建议不要将全球变量传递给函数的书。