Почему не делают заголовочные файлы C увеличивают размер двоичного файла?

Если Ваш код имеет add(0) и remove(0), используйте LinkedList, и это более симпатично addFirst() и removeFirst() методы. Иначе используйте ArrayList.

И конечно, Гуава ImmutableList является Вашим лучшим другом.

11
задан PetrosB 13 January 2010 в 19:47
поделиться

7 ответов

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

$ nm --demangle test_with_iostream
08049914 d _DYNAMIC
08049a00 d _GLOBAL_OFFSET_TABLE_
08048718 t global constructors keyed to main
0804883c R _IO_stdin_used
         w _Jv_RegisterClasses
080486d8 t __static_initialization_and_destruction_0(int, int)
08048748 W MyClass::MyClass()
         U std::string::size() const@@GLIBCXX_3.4
         U std::string::operator[](unsigned int) const@@GLIBCXX_3.4
         U std::ios_base::Init::Init()@@GLIBCXX_3.4
         U std::ios_base::Init::~Init()@@GLIBCXX_3.4
080485cc t std::__verify_grouping(char const*, unsigned int, std::string const&)
0804874e W unsigned int const& std::min<unsigned int>(unsigned int const&, unsigned int const&)
08049a3c b std::__ioinit
08049904 d __CTOR_END__
... (remaining output snipped) ...

( - demangle принимает имена функций C ++ » искажено компилятором и дает более значимые имена. Первый столбец - это адрес, если функция включена в исполняемый файл. Второй столбец - это тип. «t» - это код в сегменте «текст». «U» являются символами, связанными из других мест; в данном случае из общей библиотеки C ++.)

Сравните это с функциями, сгенерированными из вашего исходного файла без включения iostream :

$ nm --demangle test_without_iostream
08049508 d _DYNAMIC
080495f4 d _GLOBAL_OFFSET_TABLE_
080484ec R _IO_stdin_used
         w _Jv_RegisterClasses
0804841c W MyClass::MyClass()
080494f8 d __CTOR_END__
... (remaining output snipped) ...

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

Когда исходный файл включает только stdio.h , сгенерированный двоичный файл аналогичен тесту без iostream , поскольку стандартная библиотека ввода-вывода C не требует дополнительной инициализации сверх того, что уже происходит в динамической библиотеке C. Вы можете увидеть это, посмотрев на выходные данные нм , которые идентичны.

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

18
ответ дан 3 December 2019 в 01:29
поделиться

Заголовочные файлы обычно представляют собой просто объявления и не приводят непосредственно к созданию машинного кода. Компоновщик достаточно умен, чтобы не извлекать неиспользуемые функции из CRT, поэтому простое включение stdio.h без использования какой-либо из его функций не приведет к увеличению кода в вашем исполняемом файле.

РЕДАКТИРОВАТЬ: Они могут включать встроенные функции, классы, и т.д., которые включают код, но они не должны приводить к увеличению размера вашего исполняемого файла, пока они не будут фактически использованы.

9
ответ дан 3 December 2019 в 01:29
поделиться

В iostream есть некоторые статические инициализации, а в stdio.h есть только функции и их определения. Поэтому включение iostream приведет к созданию исполняемого файла большего размера.

3
ответ дан 3 December 2019 в 01:29
поделиться

iostream включает код. stdio.h - нет.

Более конкретно, следующие определения в iostream (их больше, чем указано в списке и зависят от компилятора) ссылаются на объекты, созданные в стандартной библиотеке, которые затем связываются с вашим кодом:

extern istream &cin;
extern ostream &cout;
extern ostream &cerr;
extern ostream &clog;
7
ответ дан 3 December 2019 в 01:29
поделиться

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

struct foo {
  int x;
};

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

Фактически, наличие всего, что генерирует код, обычно приводит к ошибке. Например:

void foo() {
  printf("bar!\n");
}

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

Обратите внимание, что одним исключением здесь являются встроенные члены в C ++. Например:

class Foo {
  void bar() { /* ... */ }
};

С технической точки зрения bar () создается в каждом файле, который включает этот код. Компилятор использует различные приемы, чтобы избежать ошибки (слабая привязка и т. Д.). Это действительно может увеличить размер исполняемого файла, и это, вероятно, то, что вы видели с .

2
ответ дан 3 December 2019 в 01:29
поделиться

Заголовок содержит несколько объектов, 'std :: cin , 'std :: cout , std :: cerr и std :: clog . Это экземпляры классов, которые имеют нетривиальные конструкторы и деструкторы. Это код, и его необходимо связать. Это то, что увеличивает размер исполняемого файла.

AFAIK, не поставляется с кодом, поэтому размер исполняемого файла не увеличивается.

1
ответ дан 3 December 2019 в 01:29
поделиться

В файле iostream объявлены некоторые глобальные объекты:

std :: cout, std :: cerr, std :: cin, которые относятся к типу ostream .

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

0
ответ дан 3 December 2019 в 01:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: