Глобальные переменные в C - PullRequest
2 голосов
/ 04 октября 2010

Еще один вопрос новичка; Считается ли плохим вкусом использовать много глобальных переменных в C? Я предполагаю, что ответ, вероятно, да, с другой стороны, использование основной или некоторой другой функции в качестве «базовой функции» для хранения указателей / значений с глобальной областью видимости создает целый беспорядок с указателями на указатели и т. Д. Есть мысли?

Ответы [ 6 ]

3 голосов
/ 04 октября 2010

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

Эта страница является хорошим ресурсом по ряду других причин, почему глобальные переменные плохие, хотятоже.

2 голосов
/ 04 октября 2010

Обычно большинство программистов ожидают, что функции будут pure, что означает, что вывод функции будет полностью определен ее вводом.Предоставляя им состояния, вы можете ввести в заблуждение других, которые будут использовать ваш код.Это относится к переменным static, объявленным в функциях.

А для реальных глобальных переменных (объявленных вне функций) это то, что сказал Руэль.Будьте осторожны с многопоточностью.

1 голос
/ 04 октября 2010

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

Всегда есть возможность объединить все глобалы в одну большую структуру и передать эту структуру вокруг.Но тогда какой смысл?

Вы хотели бы сгруппировать их в структуры, а затем начинаете обнаруживать: «Эй, мне нужна эта информация и в другой структуре, потому что она нужна одной глупой функции».Тогда вы думали, что решили проблему, объединив две структуры.Затем вы обнаружили, что, наконец, вы все еще застряли с большой частью структуры.

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

Например, я хотел бы написать процедуру для управления принтерами в компании.Существуют

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

И это функциональные возможности

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

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

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

Позвольте мне привести ниже пример с упрощенной (возможно, неполной) реализацией,Когда вы планируете свой проект в ER и документируете его, это значительно упрощает программирование и усовершенствование.В этот век гибкой разработки вы должны быть в состоянии выпустить полезную частичную реализацию проекта.например, вы бы сказали своему руководителю проекта следующие этапы

  • Неделя 1: Маршрутизация используемых принтеров для струйных и лазерных принтеров
  • Неделя 2: Маршрутизация используемых принтеров для архаичных ударных принтеров
  • week3: используемые задания сканирования
  • week5-7: используемые задания факса
  • week8: перенаправление недоброкачественных заданий
  • week9: перенаправление запеченных заданий на 90%
  • week9-11: незавершенное сопровождение

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

Тогда, если вы не пишете встроенный код или код ядра, вы очень скоро перейдете на C ++, гарантировано.

struct Printer{
  id,
  printType,
  location,
  *maintenance,
  *driver
}

struct Job{
  type,
  requestor,
  location
}

struct Location{
  building,
  floor,
  suite,
  lane
}

struct PrintType{
  ink,
  colour
}

struct JobStatus{
  job,
  location,
  endStatus
}

struct Maintenance{
  inkLevel,
  schedule
}

union InkLevel{
  HPDeskJetInk,
  HPLaserJetInk,
  OlivettiFabric,
  BrotherCellophane,
  etc, etc
}

enum Ink{
  FABRICImpact,
  CELLOPHANEImpact,
  INKJet,
  LASER
}

enum Colour{
  GREY,
  COLOUR
}

enum EndStatus{
  PRINTING,
  COMPLETED,
  FAILED,
  REROUTED
}

/* print will look at Job to determine the appropriate location */
JobStatus* print(job);

/* a callback to requestor indicating completion status */
JobStatus* printCallback();

/* a fax send event detected and fax function will find the appropriate server for the Job */
JobStatus* fax(job);

/* a photocopy to file job */
JobStatus* scan(job);

Maintenance* maintain(Printer);
1 голос
/ 04 октября 2010

Используйте глобальные переменные, если это крайне необходимо. Если у вас есть что-то, что нужно в глобальном масштабе, не стесняйтесь.

0 голосов
/ 04 октября 2010

Плохо использовать любые глобальные переменные на любом языке.

0 голосов
/ 04 октября 2010

Хотя C дает вам полную свободу объявлять все глобально, он поможет вам с кодированием и обслуживанием, если вы будете думать в терминах « абстрактный тип данных », который также может быть реализован на процедурных языках.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...