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

时间:2022-08-24 16:15:05

Consider following function declaration:

考虑下面的函数声明:

int abmeld(char *strsend)

which is called like this

是这样的吗?

abmeld(str);

where str is a global variable declared and initialised at the start of the program file (after the includes) like this:

其中str是在程序文件(包含后)开始时声明和初始化的全局变量:

char str[300] = "";

Now I already know this is unnecessary code (you can access and modify the char array from within any function without passing it anyways), but is this actually otherwise problematic?

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

Are there consequences (like hard error possibilities, or undefined behavior) that can happen as the result of passing an already globally scoped variable to a function?

将一个已经全局作用域的变量传递给一个函数,是否会产生一些后果(比如硬错误可能性或未定义的行为)?

7 个解决方案

#1


29  

I would say the opposite, it is almost never problematic to pass a global to a function (and it is usually dirty to use a lot of globals, the code becoming unreadable).

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

A function which depends lightly (or not at all) on the global state is often more readable and more understandable than a function using a lot of global (or even static) variables. A global variable changed in many functions makes your program messy to understand.

与使用大量全局(甚至静态)变量的函数相比,稍微依赖全局状态(或根本不依赖全局状态)的函数通常更容易读懂,也更容易理解。一个全局变量在许多函数中发生了变化,这使得您的程序难以理解。

(never forget that you code not only for the computer, but also for your colleagues -perhaps even yourself in a few months- who would have to improve your source code)

(永远不要忘记,您不仅为计算机编写代码,还为您的同事编写代码——甚至可能是您自己——谁将不得不改进您的源代码)

Also, functions using global state are typically not reentrant.

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

At last, undefined behavior is mostly orthogonal to global vs argument data. In particular, a buffer overflow can occur both with a global variable, or with a pointer to some array (such as an argument or some local variable) .

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

A very crude rule of thumb would be to avoid loading the developer's brain with more than 7 items (magical number 7, + or - 2); hence the folklore rule to avoid more than 7 arguments or more than 7 globals.

一个非常粗略的经验法则是避免在开发人员的大脑中加载超过7个条目(魔法数字7,+或- 2);因此民俗规则避免超过7个论点或超过7个球。

#2


10  

There is a case where this could be problematic: if abmeld already does something with the str global. As a trivial example:

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

extern char str[300];

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

then abmeld(str) has undefined behavior, because snprintf has undefined behavior when its destination buffer overlaps any of its inputs.

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

This demonstrates one of the reasons global variables are troublesome: in order to know what's safe to pass as an argument to abmeld, you have to know not only that it writes to str (which would surely be documented), but how it does that — it could have been written

这说明了全局变量之所以麻烦的原因之一:为了知道将什么作为参数传递给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;
}

and then it would have well-defined behavior no matter what s points to, as long as it's a valid C-string.

然后它会有定义良好的行为不管s指向什么,只要它是有效的C-string。

#3


8  

Now I already know this is unnecessary code (you can access and modify the char array from within any function without passing it anyways), but is this actually otherwise problematic?

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

It doesn't matter to the function whether it receives locally or globally defined variable. Issues with global variables are related sometimes to the fact that you might not know from which parts of the program you are accessing/changing its value. Thread safety maybe also relevant.

无论函数接收局部变量还是全局定义变量,它都是无关紧要的。全局变量的问题有时与这样一个事实有关,即您可能不知道正在访问或更改程序的哪些部分。线程安全性也可能相关。

#4


7  

It's very, VERY common to pass globals to functions. Example:

传递全局函数是很常见的。例子:

const char* global = "Example";

void foo() {
  printf("%s\n",  global );
}

Obviously this passes a global to printf. The C language by design makes this usage safe. A buggy implementation that trips over this would quickly be called out.

显然,这将传递一个全局到printf。C语言的设计使这种用法变得安全。一个错误的实现会很快被调用。

#5


6  

No, not at all.

不,不是。

Now I already know this is unnecessary code

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

Not always. In the case when your function does not have a default argument, then you have to comply with the function prototype and pass the global variable. The function won't care, whether the pointer points to local or global variable, though.

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

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

#6


3  

You want to pass global variable to the function. It's simple that function you are using, requires parameter then you have to pass the parameters of the type of the argument that is required in the function.

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

Here, there is no concern or issue for passing a global variable or a local variable. You have to take care of the datatype of the argument that is to be passed.

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

#7


2  

  1. The method abmeld(char *) is only supposed to modify/work with the argument provided to it. While it may be bad to pass a global variable to this method, yet that doesn't prohibit anyone from calling this method with any other char *.

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

    • For example, if this method checks whether the string pointed to is palindrome, then writing this method exemplifies good coding. Now anyone can call it every time he/she wants to know whether the string is palindrome or not.
    • 例如,如果该方法检查指向的字符串是否为palindrome,那么编写这个方法就可以说明良好的编码。现在任何人都可以在想知道字符串是否为回文序列时调用它。
  2. Now I already know this is unnecessary code (you can access and modify the char array from within any function without passing it anyways), but is this actually otherwise problematic?

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

    • It may not be unnecessary code as explained above. The purpose of writing a new method is to compartmentalize one piece of work. In other words, a method should do only one thing. Unless the method abmeld(char *) has been written to exclusively modify that particular global variable (and even that may be a good thing), the code is perfectly ok the way it has been written as long as it is doing one thing with the argument provided to it.

      它可能不是上面解释的不必要的代码。编写一种新方法的目的是将一项工作分成几个部分。换句话说,一个方法应该只做一件事。除非已经编写了abmeld(char *)方法来专门修改这个特定的全局变量(甚至这可能是一件好事),否则代码完全可以按照它所写的方式来编写,只要它在提供给它的参数中做一件事。

    • There are numerous examples where this code may be problematic and the problems are intuitive. For example, there may be more methods which may be modifying/working on the global string. But, those problems are the problems which arise whenever you use a global variable. To get rid of those issues, you have to get rid of the global var and not the method because it isn't the method's fault that it is being used with a global var.

      在很多例子中,这些代码可能会有问题,问题是直观的。例如,可能有更多的方法正在修改/处理全局字符串。但是,这些问题是当你使用全局变量时出现的问题。为了消除这些问题,您必须去掉全局var而不是方法,因为它与全局var一起使用并不是方法的错误。

  3. Are there consequences (like hard error possibilities, or undefined behavior) that can happen as the result of passing an already globally scoped variable to a function?

    将一个已经全局作用域的变量传递给一个函数,是否会产生一些后果(比如硬错误可能性或未定义的行为)?

    • Cannot say this authoritatively but I don't know of any. Didn't read any book either which advised against passing global vars to functions.
    • 不能这么说,但我不知道。也没有读过任何建议不要将全局vars传递给函数的书。

#1


29  

I would say the opposite, it is almost never problematic to pass a global to a function (and it is usually dirty to use a lot of globals, the code becoming unreadable).

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

A function which depends lightly (or not at all) on the global state is often more readable and more understandable than a function using a lot of global (or even static) variables. A global variable changed in many functions makes your program messy to understand.

与使用大量全局(甚至静态)变量的函数相比,稍微依赖全局状态(或根本不依赖全局状态)的函数通常更容易读懂,也更容易理解。一个全局变量在许多函数中发生了变化,这使得您的程序难以理解。

(never forget that you code not only for the computer, but also for your colleagues -perhaps even yourself in a few months- who would have to improve your source code)

(永远不要忘记,您不仅为计算机编写代码,还为您的同事编写代码——甚至可能是您自己——谁将不得不改进您的源代码)

Also, functions using global state are typically not reentrant.

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

At last, undefined behavior is mostly orthogonal to global vs argument data. In particular, a buffer overflow can occur both with a global variable, or with a pointer to some array (such as an argument or some local variable) .

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

A very crude rule of thumb would be to avoid loading the developer's brain with more than 7 items (magical number 7, + or - 2); hence the folklore rule to avoid more than 7 arguments or more than 7 globals.

一个非常粗略的经验法则是避免在开发人员的大脑中加载超过7个条目(魔法数字7,+或- 2);因此民俗规则避免超过7个论点或超过7个球。

#2


10  

There is a case where this could be problematic: if abmeld already does something with the str global. As a trivial example:

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

extern char str[300];

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

then abmeld(str) has undefined behavior, because snprintf has undefined behavior when its destination buffer overlaps any of its inputs.

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

This demonstrates one of the reasons global variables are troublesome: in order to know what's safe to pass as an argument to abmeld, you have to know not only that it writes to str (which would surely be documented), but how it does that — it could have been written

这说明了全局变量之所以麻烦的原因之一:为了知道将什么作为参数传递给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;
}

and then it would have well-defined behavior no matter what s points to, as long as it's a valid C-string.

然后它会有定义良好的行为不管s指向什么,只要它是有效的C-string。

#3


8  

Now I already know this is unnecessary code (you can access and modify the char array from within any function without passing it anyways), but is this actually otherwise problematic?

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

It doesn't matter to the function whether it receives locally or globally defined variable. Issues with global variables are related sometimes to the fact that you might not know from which parts of the program you are accessing/changing its value. Thread safety maybe also relevant.

无论函数接收局部变量还是全局定义变量,它都是无关紧要的。全局变量的问题有时与这样一个事实有关,即您可能不知道正在访问或更改程序的哪些部分。线程安全性也可能相关。

#4


7  

It's very, VERY common to pass globals to functions. Example:

传递全局函数是很常见的。例子:

const char* global = "Example";

void foo() {
  printf("%s\n",  global );
}

Obviously this passes a global to printf. The C language by design makes this usage safe. A buggy implementation that trips over this would quickly be called out.

显然,这将传递一个全局到printf。C语言的设计使这种用法变得安全。一个错误的实现会很快被调用。

#5


6  

No, not at all.

不,不是。

Now I already know this is unnecessary code

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

Not always. In the case when your function does not have a default argument, then you have to comply with the function prototype and pass the global variable. The function won't care, whether the pointer points to local or global variable, though.

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

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

#6


3  

You want to pass global variable to the function. It's simple that function you are using, requires parameter then you have to pass the parameters of the type of the argument that is required in the function.

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

Here, there is no concern or issue for passing a global variable or a local variable. You have to take care of the datatype of the argument that is to be passed.

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

#7


2  

  1. The method abmeld(char *) is only supposed to modify/work with the argument provided to it. While it may be bad to pass a global variable to this method, yet that doesn't prohibit anyone from calling this method with any other char *.

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

    • For example, if this method checks whether the string pointed to is palindrome, then writing this method exemplifies good coding. Now anyone can call it every time he/she wants to know whether the string is palindrome or not.
    • 例如,如果该方法检查指向的字符串是否为palindrome,那么编写这个方法就可以说明良好的编码。现在任何人都可以在想知道字符串是否为回文序列时调用它。
  2. Now I already know this is unnecessary code (you can access and modify the char array from within any function without passing it anyways), but is this actually otherwise problematic?

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

    • It may not be unnecessary code as explained above. The purpose of writing a new method is to compartmentalize one piece of work. In other words, a method should do only one thing. Unless the method abmeld(char *) has been written to exclusively modify that particular global variable (and even that may be a good thing), the code is perfectly ok the way it has been written as long as it is doing one thing with the argument provided to it.

      它可能不是上面解释的不必要的代码。编写一种新方法的目的是将一项工作分成几个部分。换句话说,一个方法应该只做一件事。除非已经编写了abmeld(char *)方法来专门修改这个特定的全局变量(甚至这可能是一件好事),否则代码完全可以按照它所写的方式来编写,只要它在提供给它的参数中做一件事。

    • There are numerous examples where this code may be problematic and the problems are intuitive. For example, there may be more methods which may be modifying/working on the global string. But, those problems are the problems which arise whenever you use a global variable. To get rid of those issues, you have to get rid of the global var and not the method because it isn't the method's fault that it is being used with a global var.

      在很多例子中,这些代码可能会有问题,问题是直观的。例如,可能有更多的方法正在修改/处理全局字符串。但是,这些问题是当你使用全局变量时出现的问题。为了消除这些问题,您必须去掉全局var而不是方法,因为它与全局var一起使用并不是方法的错误。

  3. Are there consequences (like hard error possibilities, or undefined behavior) that can happen as the result of passing an already globally scoped variable to a function?

    将一个已经全局作用域的变量传递给一个函数,是否会产生一些后果(比如硬错误可能性或未定义的行为)?

    • Cannot say this authoritatively but I don't know of any. Didn't read any book either which advised against passing global vars to functions.
    • 不能这么说,但我不知道。也没有读过任何建议不要将全局vars传递给函数的书。