Определение глобальной константы в C++
Я хочу определить константу в C++, которая будет видна в нескольких исходных файлах. Я могу представить следующие способы определить его в заголовочном файле:
#define GLOBAL_CONST_VAR 0xFF
int GLOBAL_CONST_VAR = 0xFF;
- некоторые функции, возвращающие значение (например,
int get_GLOBAL_CONST_VAR()
) enum { GLOBAL_CONST_VAR = 0xFF; }
const int GLOBAL_CONST_VAR = 0xFF;
-
extern const int GLOBAL_CONST_VAR;
и в одном исходном файлеconst int GLOBAL_CONST_VAR = 0xFF;
Вариант (1) - это определенно не тот вариант, который вы хотели бы используйте
Option (2) - Определение экземпляра переменной в каждом объектном файле с помощью заголовочного файла
Вариант (3) - IMO в большинстве случаев заканчивается убийством
Вариант (4) - во многих случаях может быть не очень хорошо, так как перечисление не имеет конкретного типа (C++0X добавит возможность определить тип)
так в большинстве случаев мне нужно выбрать между (5) и (6). Мои вопросы:
- что вы предпочитаете (5) или (6)?
- почему (5) в порядке, в то время как (2) нет?
9 ответов:
(5) говорит именно то, что вы хотите сказать. Плюс это позволяет компилятору оптимизировать его большую часть времени. (6) с другой стороны, не позволит компилятору когда-либо оптимизировать его, потому что компилятор не знает, измените ли вы его в конечном итоге или нет.
определенно идите с опцией 5-это типобезопасно и позволяет компилятору оптимизировать (не берите адрес этой переменной :) также, если он находится в заголовке - вставьте его в пространство имен, чтобы не загрязнять глобальную область:
// header.hpp namespace constants { const int GLOBAL_CONST_VAR = 0xFF; // ... other related constants } // namespace constants // source.cpp - use it #include <header.hpp> int value = constants::GLOBAL_CONST_VAR;
(5) "лучше", чем (6), потому что он определяет
GLOBAL_CONST_VAR
Как интегральное постоянное выражение (ICE) во всех единицах перевода. Например, вы сможете использовать его как размер массива и как метку case во всех единицах перевода. В случае (6)GLOBAL_CONST_VAR
будет лед только в той единице перевода, где он определен и только после точки определения. В других переводческих единицах он не будет работать как лед.Однако имейте в виду, что (5) дает
GLOBAL_CONST_VAR
внутренняя связь, значение что "адрес идентичности"GLOBAL_CONST_VAR
будет разным в каждой единице перевода, т. е.&GLOBAL_CONST_VAR
дадут вам другое значение указателя в каждой единице перевода. В большинстве случаев использования это не имеет значения, но если вам понадобится постоянный объект, который имеет согласованную глобальную "адресную идентичность", тогда вам придется пойти с (6), жертвуя льдом константы в этом процессе.кроме того, когда ЛЕДНОСТЬ константы не является проблемой (не является целочисленным типом) и размер тип становится больше (не скалярный тип), тогда (6) обычно становится лучшим подходом, чем (5).
(2) не в порядке, потому что
GLOBAL_CONST_VAR
in (2) имеет внешнюю связь по умолчанию. Если вы поместите его в заголовочный файл, вы, как правило, в конечном итоге с несколькими определениямиGLOBAL_CONST_VAR
, что является ошибкой.const
объекты в C++ имеют внутреннюю связь по умолчанию, поэтому (5) работает (и именно поэтому, как я сказал выше, вы получаете отдельный, независимыйGLOBAL_CONST_VAR
в каждой единице трансляции).
Если это будет константа, то вы должны отметить его как константу - вот почему 2 плохо, на мой взгляд.
компилятор может использовать константу значения для расширения некоторых математических операций и других операций, использующих это значение.
выбор между 5 и 6 - м; 5 лучше меня.
в 6) значение излишне отделено от его объявления.
обычно у меня есть один или несколько из этих заголовков, которые только определяет константы и т. д. В них, а затем никаких других "умных" вещей - хороших легких заголовков, которые можно легко включить в любом месте.
чтобы ответить на ваш второй вопрос:
(2) является незаконным, потому что это нарушает правило одного определения. Он определяет
GLOBAL_CONST_VAR
в каждом файле, где он включен, т. е. более одного раза. (5) является законным, потому что он не подчиняется правилу одного определения. КаждыйGLOBAL_CONST_VAR
- это отдельное определение, локальное для того файла, в который оно включено. Конечно, все эти определения имеют одно и то же имя и значение, но их адреса могут отличаться.
Если вы используете C++11 или более поздней версии, попробуйте использовать константы времени компиляции:
constexpr int GLOBAL_CONST_VAR{ 0xff };
Это зависит от ваших требований. (5) является лучшим для большинства нормального использования, но часто приводит к постоянному занятию места для хранения в каждом объектном файле. (6) можете обойти это в ситуациях, когда это важно.
(4) также является достойным выбором, если ваш приоритет гарантирует, что место для хранения никогда не выделяется, но он работает только для интегральных констант, конечно.
#define GLOBAL_CONST_VAR 0xFF // this is C code not C++ int GLOBAL_CONST_VAR = 0xFF; // it is not constant and maybe not compilled Some function returing the value (e.g. int get_LOBAL_CONST_VAR()) // maybe but exists better desision enum { LOBAL_CONST_VAR = 0xFF; } // not needed, endeed, for only one constant (enum elms is a simple int, but with secial enumeration) const int GLOBAL_CONST_VAR = 0xFF; // it is the best extern const int GLOBAL_CONST_VAR; //some compiller doesn't understand this