#c #map #initialization #constants
#c #словарь #инициализация #константы
Вопрос:
Я работаю на C с BCC32. Я инициализировал карту примерно с 1000 такими записями:
extern map<string, string> city ;
void region_init_0 (void) {
city["abc01"] = "Brussels" ;
city["xyz03"] = "Liege" ;
...
}
Длина файла .cpp составляет 40 КБ. После компиляции я получаю obj-файл размером 2,2 МБ. После соединения с другими модулями exe-файл также стал на 2 МБ длиннее, чем до того, как я добавил карту. Я не понимаю, почему я получаю это соотношение 50 между длиной объектного кода и общей длиной строк ASCII.
Как я могу это уменьшить? Я предполагаю, что должны быть более умные способы инициализации карты, которая будет оставаться постоянной во время выполнения программы.
Спасибо.
Комментарии:
1. Оптимизация компилятора должна уменьшить размер двоичного файла, если вы его еще не используете.
2. Файл obj размером 2,2 МБ скомпилирован с помощью того cpp-файла, который вы указали?
3. Попробуйте также обойтись без символов отладки или удалить исполняемый файл.
4. Вы думали о загрузке данных из файла во время выполнения вместо этого?
5. оптимизация компилятора @flipchart часто приводит к увеличению размера объектного файла. Отключение или чередование отладочной информации значительно сократит ее за счет невозможности использования отладчика в коде.
Ответ №1:
Вы включили оптимизацию в свой компилятор?
Возможно, у вас мог бы быть какой-нибудь код вроде
typedef std::pair<const char*,const char*> paircstr_t;
const paircstr_t initarr[] = {
{ "abc01", "Brussels" },
{ "xyz02", "Paris" },
/// etc...
{ (const char*)0, (const char*)0 } // terminating null placeholder
};
extern map<string, string> city ;
void region_init_0 (void) {
for (int i = 0;; i ) {
const char* curname = initarr[i].first;
const char* curcity = initarr[i].second;
if (!curname || !curcity) break;
map[curname] = curcity;
}
}
Размер объектного кода может быть меньше, но размер кучи среды выполнения не изменится.
Комментарии:
1. 1. Я думаю, было бы целесообразно заменить пару массивом размером 2. Компилятор может забыть оптимизировать конструктор pair.
2. В GCC пара представляет собой структуру из двух элементов.
3. Ах. Итак, конструктора нет … правильно. Тогда разницы быть не должно.
4. На самом деле, это приводит к сбою GCC 4.6.2, поэтому я сообщил gcc.gnu.org/bugzilla/show_bug.cgi?id=51092
5. Действительно, объявление
strcut paircstr_t { const char*name; const char*city; }
могло бы быть лучше.
Ответ №2:
Просто предположение: является ли operator[] встроенным? Надеюсь, вы можете изменить это, (не) определив некоторую константу препроцессора. Выпускная сборка больше или меньше debug?
Ответ №3:
Просто используйте внешнюю функцию и передайте ей необработанные cstrings:
extern std::map<std::string, std::string> city;
/* somehow make sure it cannot be inlined */
extern void AddCity(const char* const a, const char* const b) __attribute__((__noinline__));
void region_init_0 (void) {
AddCity("abc01","Brussels");
AddCity("xyz03","Liege");
...
}
extern void AddCity(const char* const a, const char* const b) {
city[a] = b;
}
Я смоделировал ваш случай в своей системе, и это уменьшило размер исполняемого файла с 924 КБ до 100 КБ (урезанный). Одно из отличий моделирования заключается в том, что вы экспортируете больше строк, поэтому соотношение не будет равным.
Комментарии:
1. Большое спасибо. Я последовал этому примеру, и файл .obj лишь немного больше, чем файл .cpp, и сгенерированный файл .exe тоже подходит. Отлично!
Ответ №4:
Вы добавили много кода. В объектном файле есть не только строки, но и сгенерированный код и, возможно, отладочная информация (например, информация о номере строки) для каждой строки. Все складывается.
Это также очень плохой способ инициализации карты; если это не машинный код, вы не захотите его писать. (И хотя, возможно, здесь нет проблемы, это означает, что карта не может быть const
.) Более типичным решением для инициализации карты может быть что-то вроде:
struct MapInitializer
{
typedef std::map<std::string, std::string> MapType
char const* key;
char const* value;
operator MapType::value_type() const
{
return MapType::value_type(key, value);
}
};
static MapInitializer initialValues[] =
{
{ "abc01", "Brussels" },
{ "xyz03", "Liege" },
// ...
};
и затем:
std::map<std::string, std::string> city(
std::begin( initialValues ), std::end( initialValues ) );
(Если инициализацию необходимо отложить до более позднего вызова функции, то:
city = std::map<std::string, std::string>(
std::begin( initialValues ), std::end( initialValues ) );
может использоваться. Но, как правило, если карта должна быть инициализирована с помощью
список констант времени компиляции, лучше всего сделать это в определении
переменная, как указано выше.)