Подтвердить что ты не робот

Пропускает ли глобальные переменные функции проблематично?

Рассмотрим следующее объявление функции:

int abmeld(char *strsend)

который называется так

abmeld(str);

где str - это глобальная переменная, объявленная и инициализируемая в начале файла программы (после включения) следующим образом:

char str[300] = "";

Теперь я уже знаю, что это ненужный код (вы можете получить доступ и модифицировать массив char из любой функции, не передавая его в любом случае), но действительно ли это в противном случае проблематично?

Имеются ли последствия (например, проблемы с жесткой ошибкой или поведение undefined), которые могут произойти в результате передачи переменной с областью с глобальным охватом в функцию?

4b9b3361

Ответ 1

Я бы сказал, наоборот, почти никогда не проблематично передавать глобальное значение функции (и обычно грязно использовать много глобалов, код становится нечитаемым).

Функция, которая легко или совсем не зависит от глобального состояния, часто более читаема и более понятна, чем функция, использующая множество глобальных (или даже статических) переменных. Глобальная переменная, измененная во многих функциях, делает вашу программу беспорядочной для понимания.

(никогда не забывайте, что вы кодируете не только компьютер, но и своих коллег - возможно, даже через несколько месяцев - кто должен улучшить исходный код)

Кроме того, функции, использующие глобальное состояние, обычно не являются реентерабельными.

Наконец, undefined поведение в основном ортогонально глобальным данным аргумента vs. В частности, переполнение буфера может происходить как с глобальной переменной, так и с указателем на некоторый массив (например, аргумент или некоторая локальная переменная).

Очень грубое правило состоит в том, чтобы избежать загрузки мозгом разработчика более 7 предметов (магическое число 7, + или - 2); следовательно, правило фольклора позволяет избежать более 7 аргументов или более 7 глобальных переменных.

Ответ 2

Есть случай, когда это может быть проблематично: если abmeld уже что-то делает с str глобальным. В качестве тривиального примера:

extern char str[300];

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

тогда abmeld(str) имеет поведение undefined, потому что snprintf имеет поведение undefined, когда его целевой буфер перекрывает любые его входы.

Это демонстрирует одну из причин, по которым глобальные переменные являются сложными: для того, чтобы знать, что безопасно передавать в качестве аргумента для 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-строка.

Ответ 3

Теперь я уже знаю, что это ненужный код (вы можете получить доступ и изменить массив char из любой функции, не передавая его в любом случае), но действительно ли это проблематично?

Для функции не имеет значения, получает ли она локальную или глобально определенную переменную. Проблемы с глобальными переменными иногда связаны с тем, что вы не знаете, из каких частей программы вы обращаетесь/изменяете ее значение. Возможно, также важна безопасность потока.

Ответ 4

Это очень, очень распространено, чтобы передавать глобальные функции. Пример:

const char* global = "Example";

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

Очевидно, что это передает глобальное значение printf. Язык C по дизайну делает это использование безопасным. Быстрое обращение к этой ошибке будет вызвано ошибкой.

Ответ 5

Нет, совсем нет.

Теперь я уже знаю, что это ненужный код

Не всегда. В случае, когда ваша функция не имеет аргумента по умолчанию, вы должны выполнить прототип функции и передать глобальную переменную. Функция не волнует, указывает ли указатель на локальную или глобальную переменную.

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

Вы хотите передать глобальную переменную функции. Простая функция, которую вы используете, требует параметра, тогда вы должны передать параметры типа аргумента, который требуется в этой функции.

Здесь нет никакой проблемы или проблемы для передачи глобальной переменной или локальной переменной. Вы должны позаботиться о типе данных аргумента, который должен быть передан.

Ответ 7

  • Метод abmeld(char *) должен только модифицировать/работать с предоставленным ему аргументом. Хотя может быть плохо передать глобальную переменную этому методу, но это не запрещает кому-либо звонить этот метод с любым другим char *.

    • Например, если этот метод проверяет, является ли указанная строка палиндромом, тогда этот метод иллюстрирует хорошее кодирование. Теперь каждый может называть его каждый раз, когда он/она хочет знать, является ли строка палиндром или нет.
  • Теперь я уже знаю, что это ненужный код (вы можете получить доступ и модифицировать массив char из любой функции, не передавая его в любом случае), но действительно ли это проблематично?

    • Это может быть не лишний код, как описано выше. Целью написания нового метода является разделение одной части работы. Другими словами, метод должен делать только одно. Если метод abmeld(char *) не был написан для исключительного изменения этой конкретной глобальной переменной (и даже это может быть хорошо), код отлично хорошо, как он был написан до тех пор, пока он делает одно с аргументом, предоставленным ему.

    • Существует множество примеров, когда этот код может быть проблематичным, а проблемы интуитивно понятны. Например, может быть больше методов, которые могут быть изменены/работают над глобальной строкой. Но эти проблемы - проблемы, возникающие всякий раз, когда вы используете глобальную переменную. Чтобы избавиться от этих проблем, вам нужно избавиться от глобального var, а не метода, потому что это не ошибка метода, которую он использует с глобальным var.

  • Имеются ли последствия (например, проблемы с жесткой ошибкой или поведение undefined), которые могут произойти в результате передачи переменной с областью с глобальным охватом в функцию?

    • Не могу сказать это авторитетно, но я ничего не знаю. Не читал ни одной книги, которая рекомендовала не передавать глобальные вары в функции.