¿Pasar variables globales a funciones es problemático?

Considere la siguiente statement de función:

int abmeld(char *strsend) 

que se llama asi

 abmeld(str); 

donde str es una variable global declarada e inicializada al inicio del archivo de progtwig (después de las inclusiones) de esta manera:

 char str[300] = ""; 

Ahora ya sé que este es un código innecesario (puede acceder y modificar la matriz de caracteres desde cualquier función sin pasarlo de todos modos), pero ¿es esto realmente problemático?

¿Hay consecuencias (como posibilidades de error o comportamiento indefinido) que pueden suceder como resultado de pasar una variable ya con scope global a una función?

Yo diría lo contrario, casi nunca es problemático pasar un global a una función (y generalmente es sucio usar muchos globales, ya que el código se vuelve ilegible).

Una función que depende ligeramente (o nada) del estado global es a menudo más legible y más comprensible que una función que usa muchas variables globales (o incluso estáticas). Una variable global modificada en muchas funciones hace que su progtwig sea complicado de entender.

(Nunca olvide que usted codifica no solo para la computadora, sino también para sus colegas, tal vez incluso para usted mismo en unos pocos meses, quienes deberían mejorar su código fuente)

Además, las funciones que utilizan el estado global normalmente no son reentrantes .

Por último, el comportamiento indefinido es en su mayoría ortogonal a los datos globales frente a argumentos. En particular, un desbordamiento de búfer puede ocurrir tanto con una variable global, como con un puntero a alguna matriz (como un argumento o alguna variable local).

Una regla general muy cruda sería evitar cargar el cerebro del desarrollador con más de 7 elementos ( número mágico 7, + o – 2 ); De ahí la regla del folklore para evitar más de 7 argumentos o más de 7 globales.

Hay un caso en el que esto podría ser problemático: si abmeld ya hace algo con la str global. Como ejemplo trivial:

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

entonces abmeld(str) tiene un comportamiento indefinido, porque snprintf tiene un comportamiento indefinido cuando su búfer de destino se superpone a cualquiera de sus entradas.

Esto demuestra una de las razones por las que las variables globales son molestas: para saber qué es seguro pasar como un argumento para abmeld , debe saber no solo que se escribe en str (que seguramente estaría documentado), sino cómo lo hace : podría haber sido escrito

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

y luego tendría un comportamiento bien definido sin importar a qué se apunta, siempre que sea una cadena en C válida.

Ahora ya sé que este es un código innecesario (puede acceder y modificar la matriz de caracteres desde cualquier función sin pasarlo de todos modos), pero ¿es esto realmente problemático?

No le importa a la función si recibe una variable definida local o globalmente. Los problemas con las variables globales a veces están relacionados con el hecho de que es posible que no sepa de qué partes del progtwig está accediendo / cambiando su valor. La seguridad del hilo también puede ser relevante.

Es muy, muy común pasar globales a las funciones. Ejemplo:

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

Obviamente esto pasa de forma global a printf . El lenguaje C por diseño hace que este uso sea seguro. Una implementación de buggy que tropieza con esto se llamaría rápidamente.

No, en absoluto.

Ahora ya sé que este es un código innecesario.

No siempre. En el caso de que su función no tenga un argumento predeterminado, debe cumplir con el prototipo de función y pasar la variable global. Sin embargo, a la función no le importará si el puntero apunta a una variable local o global.

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

Desea pasar la variable global a la función. Es simple que la función que está utilizando, requiere un parámetro, entonces tiene que pasar los parámetros del tipo de argumento que se requiere en la función.

Aquí, no hay ninguna preocupación o problema para pasar una variable global o una variable local. Debe cuidar el tipo de datos del argumento que se va a pasar.

  1. El método abmeld(char *) solo se supone que modifica / trabaja con el argumento que se le proporciona. Si bien puede ser malo pasar una variable global a este método, sin embargo, eso no prohíbe a nadie llamar a este método con ningún otro char *.

    • Por ejemplo, si este método comprueba si la cadena a la que apunta es palíndromo, al escribir este método se ejemplifica una buena encoding. Ahora cualquiera puede llamarla cada vez que quiera saber si la cadena es palíndromo o no.
  2. Ahora ya sé que este es un código innecesario (puede acceder y modificar la matriz de caracteres desde cualquier función sin pasarlo de todos modos), pero ¿es esto realmente problemático?

    • Puede que no sea un código innecesario como se explicó anteriormente. El propósito de escribir un nuevo método es compartimentar una pieza de trabajo. En otras palabras, un método debe hacer una sola cosa. A menos que se haya escrito el método abmeld(char *) para modificar exclusivamente esa variable global en particular (e incluso eso puede ser una buena cosa), el código está perfectamente bien en la forma en que se ha escrito siempre y cuando esté haciendo una cosa con el argumento proporcionado a ella.

    • Existen numerosos ejemplos en los que este código puede ser problemático y los problemas son intuitivos. Por ejemplo, puede haber más métodos que pueden estar modificando / trabajando en la cadena global. Pero, esos problemas son los problemas que surgen cuando se utiliza una variable global. Para deshacerse de esos problemas, debe deshacerse de la var global y no del método porque no es culpa del método que se use con una var global.

  3. ¿Hay consecuencias (como posibilidades de error o comportamiento indefinido) que pueden suceder como resultado de pasar una variable ya con scope global a una función?

    • No puedo decir esto con autoridad, pero no sé de ninguna. Tampoco leí ningún libro que desaconsejara pasar vars globales a las funciones.