Подтвердить что ты не робот

Накладные расходы в неиспользуемом коде

Мне интересно, какие накладные расходы связаны с неиспользуемыми функциями в вашем коде.

Скажем, например, у вас есть ведение журнала отладки, и затем вы предоставляете большинству своих объектов функцию ToString(), которая используется в журналах отладки.

В сборке релизов ведение журнала отладки не используется. Стоит ли тогда удалять исходный код этих функций ToString()? (например, через макрос?)

Или они просто делают исполняемый файл незначительно большим и в противном случае не влияют на производительность? например нет влияния скорости? Или компилятор или компоновщик возможно даже удаляют функции, если они не используются? Если компилятор или компоновщик не удаляют код, что, если функции ToString() были определены в строке? Предположительно, он попытался бы встроить код, и поскольку функция никогда не вызывается, она исчезнет?

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

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

Спасибо

4b9b3361

Ответ 1

Это зависит от компилятора и, я думаю, от уровня оптимизации.

g++ и MSVС++ удаляют неиспользуемые встроенные функции, но сохраняют неиспользуемые не встроенные функции. Например, вы используете только небольшую часть STL в обычной программе. Все неиспользуемые функции удаляются, потому что они определены как встроенные.

GCC, с другой стороны, сохраняет все функции, даже неиспользуемые встроенные.

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

Ответ 2

1. Что касается компиляторов и компоновщиков

На самом деле это зависит от того, как вы создаете свой исполняемый файл.

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

Однако, если вы связываете динамически, они будут там, потому что в отношении библиотеки они экспортируются и поэтому используются.

Что касается множественных определений, это зависит от слабости символа. Если он слабый, компоновщик выбирает одно из определений, иначе он зажимает его.

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

2. Как решить проблему?

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

Лично я бы не стал беспокоиться... особенно потому, что я тоже вхожу в Release Release (как иначе отслеживать проблемы с производством?).

Решение может состоять в том, чтобы определить функции нарушения в отдельном файле и не связывать их в Release. Примечание. Я не думаю, что он работает для виртуальных функций, поскольку они, по крайней мере, используются в vtable

Ответ 3

Линкеры удаляют повторяющиеся функции, и они удаляют ненужные данные (линкер Microsoft предлагает переключатели /OPF:REF и /OPT:ICF для настройки этих параметров).

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

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

Другим преимуществом #ifdef является то, что он переносимый и не зависит от конкретной системы компилятора: -/

Ответ 4

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