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

Mag*_*sch 22 c

考虑以下函数声明:

int abmeld(char *strsend)
Run Code Online (Sandbox Code Playgroud)

这就是这样称呼的

abmeld(str);
Run Code Online (Sandbox Code Playgroud)

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

char str[300] = "";
Run Code Online (Sandbox Code Playgroud)

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

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

Bas*_*tch 29

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

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

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

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

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

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

  • 在这方面,全局常量的危害要小得多 - 例如,它们不会影响重入. (4认同)

zwo*_*wol 10

还有就是在那里,这可能是有问题的情况:如果abmeld已经做与一些str全球性的.作为一个简单的例子:

extern char str[300];

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

然后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;
}
Run Code Online (Sandbox Code Playgroud)

s只要它是一个有效的C字符串,它就会有明确定义的行为,无论指向什么点.


gio*_*gim 8

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

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


MSa*_*ers 7

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

const char* global = "Example";

void foo() {
  printf("%s\n",  global );
}
Run Code Online (Sandbox Code Playgroud)

显然,这通过全球化printf.设计的C语言使这种用法安全.很快就会出现一个错误的实现.


Abh*_*eet 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;
}
Run Code Online (Sandbox Code Playgroud)