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

时间:2016-02-10 07:51:47

标签: c

考虑以下函数声明:

int abmeld(char *strsend)

就像这样被称为

abmeld(str);

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

char str[300] = "";

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

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

7 个答案:

答案 0 :(得分:29)

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

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

(永远不要忘记您不仅要为计算机编写代码,还要为您的同事编写代码 - 甚至可能在几个月内编写代码 - 他们必须改进您的源代码)

此外,使用全局状态的函数通常不是reentrant

最后,undefined behavior主要与全局vs参数数据正交。特别是,buffer overflow既可以使用全局变量,也可以使用指向某个数组的指针(例如参数或某个局部变量)。

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

答案 1 :(得分:10)

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

extern char str[300];

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

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

这说明了全局变量很麻烦的原因之一:为了知道作为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;
}

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

答案 2 :(得分:8)

  

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

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

答案 3 :(得分:7)

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

printf

显然,这会将全局传递给 terminal_monitor = popen("awk '{if(l1){ download=($2-l1)/1024 download_round=sprintf("%.2f kB/s", download) upload=($10-l2)/1024 upload_round=sprintf("%.2f kB/s", upload) print download_round, upload_round } else{l1=$2; l2=$10;}}' <(grep eth0 /proc/net/dev) <(sleep 1; grep eth0 /proc/net/dev)", "r"); 。 C语言按设计使这种用法安全。很快就会出现一个错误的实施方案。

答案 4 :(得分:6)

不,完全没有。

  

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

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

/* 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;
}

答案 5 :(得分:3)

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

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

答案 6 :(得分:2)

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

    • 例如,如果此方法检查指向的字符串是否为回文,则编写此方法可以说明良好的编码。现在,每当他/她想知道字符串是否是回文时,任何人都可以调用它。
  2.   

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

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

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

  3.   

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

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