Вопрос с "extern" в C - PullRequest
       1

Вопрос с "extern" в C

2 голосов
/ 28 декабря 2010

При программировании я хотел бы разделить один большой файл (который содержит основную функцию) на множество маленьких файлов, поэтому есть один общий случай: функции в маленьких файлах могут изменять var из основного файла, поэтому я думаю, что extern полезно!

например:

в main.c

 extern int i = 100;

в маленьких.c

extern int i;
fprintf(stdout, "var from main file: %d\n", i);

Я просто хочу знать, верно ли мое понимание?

Ответы [ 4 ]

6 голосов
/ 28 декабря 2010

Вам нужно изменить одну вещь, чтобы она заработала: extern int i = 100; в main.c следует изменить на int i = 100;

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

Полезная стратегия для такого рода рефакторинга: сначала переместите данные, затем переместите функции, которые используют эти данные. То есть сначала переместите переменную i в small.c, затем переместите функции, которые используют i.

Если вы хотите переместить функции, но не данные, попробуйте передать i в качестве аргумента вместо доступа к нему с помощью объявления extern.

2 голосов
/ 28 декабря 2010

Да, это возможно. Однако вместо этого:

 // moduleA.c
 int c = 5;
 void bar(void);
 void foo(void) {
     // ...
     bar();
     // ...
  }

  // moduleB.c
  extern int c; // references "c" defined in moduleA
  void bar(void) {
      // ...
      // do something with c
      // ...
   }

Почти всегда лучше сделать:

 // moduleA.c
 int c = 5;
 void bar(int);
 void foo(void) {
     // ...
     bar(c);
     // ...
  }

  // moduleB.c
  void bar(int c) {
      // ...
      // do something with c
      // ...
   }

Другими словами, хотя вы можете использовать глобальные переменные, передача переменных явно в качестве параметров намного лучше. Пожалуйста, прочитайте Глобальные переменные плохие по разным причинам, чтобы избежать глобальных переменных. Чтобы выделить несколько причин, почему глобалы плохие:

  1. Они скрывают зависимости. Например, когда ваш код ссылается на глобальную переменную «c», разработчику нужно искать повсюду, чтобы найти, где она определена и как она используется, поскольку эта переменная может быть изменена любым модулем вообще. Другими словами, это вносит ненужную сложность.

  2. Глобальные переменные являются общими для всего процесса. В то время как локальная переменная, которая передается, будет создаваться в стеке, а каждый поток имеет свой собственный стек, глобальные ресурсы совместно используют общее хранилище для всей программы. Любая функция, которая использует глобальную переменную (если эта глобальная переменная не является константой), не является реентерабельной и, если она не блокирует доступ к этой глобальной переменной, не является поточно-ориентированной. Невероятно сложно сделать программу, использующую глобальные переменные, поточно-ориентированной, и тот факт, что любой модуль может писать в глобальную переменную, означает, что трудно гарантировать, что все модули, которые записывают в переменную, блокируют ее. *

1 голос
/ 28 декабря 2010

Один файл должен содержать фактический "конкретный" int:

int i = 100;

Все остальные файлы должны содержать «внешнюю» ссылку на int:

extern int i;

Затем компоновщик должен убедиться, что все они указывают на одну и ту же ячейку памяти.

1 голос
/ 28 декабря 2010

Ты почти у цели. Вам нужно использовать только:

int i = 100;

в main.c, в противном случае вы получите ошибку компоновщика.

Объявление extern говорит компилятору не выделять место для этой переменной, но что переменная будет объявлена ​​где-то еще. Компилятор добавляет «внешнюю ссылку» в файл .o, который говорит компоновщику подключить ссылки к той же переменной.

Не позволяя компилятору создать фактический экземпляр переменной i, как вы сделали в своем вопросе, компоновщик увидит все внешние ссылки на i, но не определение из i. Компоновщик захочет увидеть ровно одно определение каждой переменной и функции.

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