объем файла и статические числа - PullRequest
1 голос
/ 10 ноября 2009

Я столкнулся с интересной проблемой в моем проекте ИИ. Я пытаюсь отформатировать отладочный текст, и происходит что-то странное. Вот блок кода:

    float ratio = 1.0f / TIME_MOD;

TIME_MOD - это статическое число с плавающей точкой, объявленное в отдельном файле. Это значение модифицируется на основе пользовательского ввода в другом классе (я убедился, что это значение изменяется при отладке в рамках функции «input»), но всякий раз, когда я пытаюсь разделить его во внешнем цикле, я получаю такое же количество. (1 делится на начальное значение TIME_MOD).

Я что-то упускаю из-за статических переменных и области видимости файла?

Ответы [ 5 ]

15 голосов
/ 10 ноября 2009

Я думаю, что есть некоторая путаница со словом "статический". У нас есть ключевое слово static, которое делает разные вещи в разных контекстах, и мы используем слово «статический», чтобы назвать один из трех классов «длительности хранения». В некоторых контекстах static не контролирует продолжительность хранения объектов, а только «связь», что, вероятно, является основной причиной путаницы.


Длительность хранения

Срок хранения - это свойство объекта.

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

  • Объекты с автоматической продолжительностью хранения могут быть определены только внутри блока в функциях. Такой объект создается, когда выполнение достигает определения. Это может происходить несколько раз (рекурсия), что создает несколько объектов. Когда выполнение покидает блок, объекты автоматически уничтожаются.

  • Динамически размещаемые объекты имеют длительность динамического хранения . В этом случае пользователь контролирует время жизни объектов с помощью нового, нового [], удаления, удаления [] и т. Д.


Связь

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


Ключевое слово "статический"

Эффект static зависит от контекста:

  • Если вы объявляете или определяете объект в глобальной области / области имен, это всегда объект со «статической продолжительностью хранения». Использование ключевого слова static в глобальной области / области имен вообще не влияет на продолжительность хранения. Вместо этого это влияет на связь. Он объявляет сущность - которая также может быть функцией - иметь внутреннюю связь. Таким образом, спецификатор класса хранилища был «неправильно использован», чтобы сделать что-то совершенно другое: обеспечить внутреннюю связь. Это своего рода противоположность extern в этом контексте. В C ++ вы можете добиться того же эффекта с помощью анонимного пространства имен. Рекомендуется использовать анонимные пространства имен над static, чтобы "минимизировать путаницу".

  • static в области видимости класса может использоваться для объявления объектов со статической продолжительностью хранения в области видимости класса. Существует только одна такая переменная, а не одна для каждого объекта.

  • static в области действия функции может использоваться для объявления объектов со статической продолжительностью хранения, которая инициализируется лениво


Если вы говорите «статическая переменная», не совсем понятно, что вы имеете в виду. Вы ссылаетесь на «статическую продолжительность хранения» или «внутреннюю связь»?

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

// myheader.hpp
extern int k; // declaring an int variable with external linkage

// foo.cpp
#include "myheader.hpp"
int k;        // defining an int variable with external linkage

// bar.cpp
#include "myheader.hpp"
int main() {
    return k;
}
2 голосов
/ 10 ноября 2009

Статическая переменная существует только в пределах текущей единицы компиляции. Удалите static из его определения и измените его на «volatile» (хотя это предполагает, что вы используете несколько потоков, если нет, вам не нужно использовать volatile), и все должно быть в порядке.

Редактировать: Ваш ответ здесь, я предполагаю, что у вас есть следующий код:

a.cpp:

static float TIME_MOD = <some value>;

B.CPP:

static float TIME_MOD = <some value>;

Если вы делаете это, TIME_MOD существует в 2 местах, и это является источником ваших проблем. Вам нужно переписать код, похожий на этот.

a.cpp:

float TIME_MOD = <some value>;

B.CPP (и C.CPP, D.CPP и т. Д.):

extern float TIME_MOD;

А затем используйте TIME_MOD как обычно. Это говорит компилятору, что TIME_MOD находится где-то еще, и не стоит беспокоиться о том, что он не знает, что в нем содержится. Затем компоновщик пройдет и «свяжет» это плавающее определение TIME_MOD с правильным определением.

Стоит также отметить, что это, вероятно, работа с "extern float TIME_MOD;" где-нибудь в заголовочном файле и включая его в любые CPP-файлы, в которых он вам нужен. Тем не менее фактическое определение (то есть не внешнее определение) сохраните в одном и только одном файле.

Это, безусловно, объясняет тот факт, что я думал, что вы извлекаете статику (что я считал невозможным).

0 голосов
/ 10 ноября 2009

Полагаю, вы объявили эту переменную в заголовочном файле как: static float TIME_MOD; И включил этот файл в cpps. Делая это, вы эффективно создали отдельные экземпляры с одинаковыми именами переменных в каждом модуле компиляции. Вы должны изменить объявление на: extern float TIME_MOD; И определите переменную в одном из cpps: float TIME_MOD = 0;

0 голосов
/ 10 ноября 2009

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

Теперь, если это так, вам не нужен статический TIME_MOD, и для разрешения конфликтов имен вы можете использовать пространства имен.

0 голосов
/ 10 ноября 2009

Вы можете изменить статическую переменную на #define и установить переменную-член в синглтоне, равную ей. Изменения и доступ будут применяться к переменной-члену синглтона.

...