将全局变量传递给函数是否有问题?
考虑以下函数声明:
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; }
您想要将全局变量传递给函数。 您正在使用的函数很简单,需要参数,然后您必须传递函数中所需参数类型的参数。
这里,传递全局变量或局部变量没有任何问题或问题。 您必须处理要传递的参数的数据类型。
-
abmeld(char *)
方法只能修改/使用提供给它的参数。 虽然将全局变量传递给此方法可能不好,但这并不禁止任何人使用任何其他char *调用此方法。- 例如,如果此方法检查指向的字符串是否为回文,则编写此方法可以说明良好的编码。 现在,每当他/她想知道该字符串是否是回文时,任何人都可以调用它。
-
现在我已经知道这是不必要的代码(你可以从任何函数中访问和修改char数组而不必传递它),但这实际上是否有问题呢?
-
如上所述,它可能不是不必要的代码。 编写新方法的目的是划分一项工作。 换句话说, 方法应该只做一件事。 除非已经编写了方法
abmeld(char *)
来专门修改那个特定的全局变量(甚至可能是一件好事),所以代码完全可以按照它的编写方式完成,只要它与提供给它的论据。 -
有许多例子,这些代码可能存在问题,而且问题很直观。 例如,可能有更多方法可能正在修改/处理全局字符串。 但是,这些问题是使用全局变量时出现的问题。 要摆脱这些问题,你必须摆脱全局变量而不是方法,因为它与全局变量一起使用不是方法的错。
-
-
是否存在可能因将已经全局范围的变量传递给函数而导致的后果(如硬错误可能性或未定义的行为)?
- 不能说这个权威,但我不知道。 没有读过任何建议不要将全球变量传递给函数的书。