Как убрать тело функции?
От: Аноним  
Дата: 31.08.02 16:28
Оценка:
Есть несколько функций:
func1()
{
...
}

func2()
{
...
}

func3()
{
...
}


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

Оговорочка: Функции большие и подтягивают за собой другие не нужные функции, так что писать так
#define func1() {......}

очень сложно(трудно читать).
Re: Как убрать тело функции?
От: Аноним  
Дата: 31.08.02 17:22
Оценка:
Здравствуйте Аноним, Вы писали:

#ifdef USE_FUNCTION_1
#undef USE_FUNCTION_1
#endif
#ifdef USE_FUNCTION_2
#undef USE_FUNCTION_2
#endif
#ifdef USE_FUNCTION_3
#undef USE_FUNCTION_3
#endif

#define USE_FUNCTION_2 // какую функцию использовать

int func()
{
#if defined( USE_FUNCTION_1 )
return func1();
#elif defined( USE_FUNCTION_2 )
return func2();
#elif defined( USE_FUNCTION_3 )
return func3();
#elif
C_ASSERT( 0 )
#endif
}

#ifdef USE_FUNCTION_1
int func1()
{
 return 1;
}
#endif // !USE_FUNCTION_1

#ifdef USE_FUNCTION_2
int func2()
{
 return 2;
}
#endif // !USE_FUNCTION_2

#ifdef USE_FUNCTION_3
int func3()
{
 return 3;
}
#endif // !USE_FUNCTION_3
Re: Как убрать тело функции?
От: Кодт Россия  
Дата: 02.09.02 12:21
Оценка:
Здравствуйте Аноним, Вы писали:

А>Есть несколько функций:


А>Но нужно часто перекомпилировать программу, используя разные функции.

А>Как можно устроить, чтобы не нужные функции не включались в код?

Распихать каждую функцию в свой .cpp файл.
Те, которые не используются — не будут линковаться.

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

А>Оговорочка: Функции большие и подтягивают за собой другие не нужные функции, так что писать так

А>#define func1() {......}

А>очень сложно(трудно читать).

Это что, у всех функций одинаковое имя?!
Вот здесь — лечится условной компиляцией, но см. мое ИМХО выше.
Перекуём баги на фичи!
Re[2]: Как убрать тело функции?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 03.09.02 04:15
Оценка:
Здравствуйте Кодт, Вы писали:

А>>Но нужно часто перекомпилировать программу, используя разные функции. Как можно устроить, чтобы не нужные функции не включались в код?


К>Распихать каждую функцию в свой .cpp файл. Те, которые не используются — не будут линковаться.

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

.cpp файлы полностью линкуются в результирующий exe-модуль. Поэтому приемлемые решения:
  1. условная компиляция с физическим удалением ненужных функций во время компиляции. Не то, чтобы совсем уж порочна, но достаточно неудобна из-за неочевидности расположения и количества констант, которые нужно определить для нужной конфигурации. Хотя если грамотно продумать, то вполне приемлемое решение.
  2. библиотека (.LIB) функций. Линкер подсоединит в EXE-модуль только нужные функции из неё. Тут только нужно расположить функции по отдельным модулям (.CPP файлам) так, чтобы они не тянули за собой не используемые функции.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[3]: Как убрать тело функции?
От: Vladik Россия  
Дата: 03.09.02 06:59
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>.cpp файлы полностью линкуются в результирующий exe-модуль. Поэтому приемлемые решения:


ИМХО зависит от компилятора. Например, VC6.0 и C++Builder, по моему опыту, "лишнее" в exe не пихают.
Как все запущенно...
Re[4]: Как убрать тело функции?
От: Flamer Кипр http://users.livejournal.com/_flamer_/
Дата: 03.09.02 07:02
Оценка:
Здравствуйте Vladik, Вы писали:

V>Здравствуйте Vi2, Вы писали:


Vi2>>.cpp файлы полностью линкуются в результирующий exe-модуль. Поэтому приемлемые решения:


V>ИМХО зависит от компилятора. Например, VC6.0 и C++Builder, по моему опыту, "лишнее" в exe не пихают.


Ну если ИМХО, то все зависит от линковщика, а не от компилятора. Компилятор компилирует модули в объектные файлы, а задача линковщика — собрать все это в исполняемый файл, попутно выявляя зависимости и исключая из процесса линковки код, который не используется...
Re[5]: Как убрать тело функции?
От: Vladik Россия  
Дата: 03.09.02 07:35
Оценка:
Здравствуйте Flamer, Вы писали:

V>>ИМХО зависит от компилятора. Например, VC6.0 и C++Builder, по моему опыту, "лишнее" в exe не пихают.

F>Ну если ИМХО, то все зависит от линковщика, а не от компилятора. Компилятор компилирует модули в объектные файлы, а задача линковщика — собрать все это в исполняемый файл, попутно выявляя зависимости и исключая из процесса линковки код, который не используется...

ИМХО это буквоедство Учитывая то, что линковщик поставляется с конкретным компилятором и понимает только его объектные файлы.
Как все запущенно...
Re[6]: Как убрать тело функции?
От: dupamid Россия  
Дата: 03.09.02 08:21
Оценка:
Здравствуйте Vladik, Вы писали:

V>ИМХО это буквоедство Учитывая то, что линковщик поставляется с конкретным компилятором и понимает только его объектные файлы.


Имеенно что буквоедство! Тем более что все зависит не только от линкера, но и от компилятора, как он уложит функции и данные в пределах одного модуля в сегменты, а то он может их уложить и перемешать так что ничего выкинуть будет нельзя.

Линкер-то обычно поставляется с конкретным компилятором, но обычно он линкует не только "свои" объектные файлы, но и любые другие объектные файлы, которые подходят ему по формату. Так как форматов объектных файлов существнно меньше чем компиляторов, то отношения компилятор:линкер не равно 1:1.
Re[4]: Как убрать тело функции?
От: adb Россия  
Дата: 03.09.02 09:25
Оценка:
Здравствуйте Vladik, Вы писали:

V>Здравствуйте Vi2, Вы писали:


Vi2>>.cpp файлы полностью линкуются в результирующий exe-модуль. Поэтому приемлемые решения:


V>ИМХО зависит от компилятора. Например, VC6.0 и C++Builder, по моему опыту, "лишнее" в exe не пихают.


Это касается только одиноко стоящих функций. Методы класса скорее всего будут линковаться (Виртуальные точно остальные наверно все таки нет). Эта технология стара как мир и называется smart linker. Собственно сейчас ее поддерживают все. Компилятор здесь действительно не причем.
Re[5]: Как убрать тело функции?
От: dupamid Россия  
Дата: 03.09.02 10:03
Оценка:
Здравствуйте adb, Вы писали:

adb>Это касается только одиноко стоящих функций. Методы класса скорее всего будут линковаться (Виртуальные точно остальные наверно все таки нет). Эта технология стара как мир и называется smart linker. Собственно сейчас ее поддерживают все. Компилятор здесь действительно не причем.


Не все так просто, если компилятор увидел, что функции содержат большие куски общего кода, то он мог частично объединить тела этих функций, в этом случае линкер ничего выкинуть не сможет.
Re[7]: Как убрать тело функции?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 03.09.02 14:15
Оценка:
Я немного отсутствовал, так что цитат много

Здравствуйте Vladik, Вы писали:

V>ИМХО зависит от компилятора. Например, VC6.0 и C++Builder, по моему опыту, "лишнее" в exe не пихают.


Ничего подобного. См. ниже.

Здравствуйте Flamer, Вы писали:

F>Ну если ИМХО, то все зависит от линковщика, а не от компилятора. Компилятор компилирует модули в объектные файлы, а задача линковщика — собрать все это в исполняемый файл, попутно выявляя зависимости и исключая из процесса линковки код, который не используется...


Выявляя, но не исключая. Он не имеет такого права. Да, в общем-то, и возможности. Не та у него стратегия. См. ниже.

Здравствуйте dupamid, Вы писали:

D>Имеенно что буквоедство! Тем более что все зависит не только от линкера, но и от компилятора, как он уложит функции и данные в пределах одного модуля в сегменты, а то он может их уложить и перемешать так что ничего выкинуть будет нельзя.


У вас высокое мнение о Линкере как о интеллектуальной программе. Это не так. Для такой программы
в test.cpp
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
     // TODO: Place code here.
    return 0;
}
в test2.cpp
void f2()
{
}
в test3.c
void f3()
{
}

вот такая карта памяти test.map
 0001:00000040       _WinMain@16                00401040 f   test.obj
 0001:000001a0       ?f2@@YAXXZ                 004011a0 f   Test2.obj
 0001:000001c0       _f3                        004011c0 f   test3.obj
 0001:000001f0       __chkesp                   004011f0 f   LIBCD:chkesp.obj

Как видите, всё присутствует, хотя и не используется.

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

Объектные файлы (.obj) ВСЕГДА включаются в состав модулей принудительно IDE-шкой или в makefile программистом. А вот модули из библиотек (.lib) включаются для разрешения какой-либо ссылки из другого модуля.

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

Каждая программная секция имеет своё имя и имеет свою стратегию сборки — добавляться, накладываться и т.п. Причём эта стартегия применяется только для объединения всех программных секций, имеющих одно имя, — вот это и имеет критическое значение для Линкера! Опции программной секции "Сбросить при том или ином условии" я не встречал, потому как она противоречит операции объединения. Есть, конечно, специфические секции, как стек и т.п., но к кодовым секциям обычно применяется операция "Добавить".

А атрибуты программных секций устанавливает Компилятор (или Программист через опции Компилятора). Сам Линкер ничего своего не добавляет в обработку секций.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[8]: Как убрать тело функции?
От: adb Россия  
Дата: 03.09.02 14:34
Оценка:
А release версию не пробовали собирать?
Re: Итог?
От: Alaxandr Россия  
Дата: 03.09.02 15:44
Оценка:
Это я <Аноним>, задавший вопрос.

Я думаю, что при компиляции всегда будут включаются ВСЕ описанные мной функции(не включение их будет недостатком линковщика), а уж использовать я их могу по своему желанию. Хотя, можно было-бы сделать фильтр(по желанию) на исключение функций, если нигде не упоминается ее имя. В классах тоже можно просчитать полиморфизм(virtual и достп к функциям), а не однозначность вызова C++ не допускает.
По поводу распихивания функций по CPP — это очень сложно, надо исключать не нужные файлы из проекта. Значит один выход — препроцессор.
Re[8]: Как убрать тело функции?
От: Vladik Россия  
Дата: 03.09.02 15:57
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>У вас высокое мнение о Линкере как о интеллектуальной программе. Это не так. Для такой программы


Vi2>в test2.cpp

Vi2>void f2()
Vi2>{
Vi2>}

Перепишем эту функцию так:

const char *f2()
{
    return "Tra-la-la";
}


Вопрос: почему в результирующем exe-шнике нет строки "Tra-la-la"?

P.S. Я не собираюсь опровергать информацию, которую ты изложил, это все очень интересно. Но видимо "интеллектуальности" в современные линкеры/компиляторы добавили (в BC3.1 такого не было). Что не так уж и плохо

P.S.S. Кстати, формат паскальных объектников, насколько я знаю, изначально предполагал определение зависимостей и выбрасывания ненужного. И было (сидя на BC3.1) обидно
Как все запущенно...
Re[2]: Итог?
От: Аноним  
Дата: 03.09.02 16:30
Оценка:
Здравствуйте Alaxandr, Вы писали:

A>Это я <Аноним>, задавший вопрос.


A>Я думаю, что при компиляции всегда будут включаются ВСЕ описанные мной функции(не включение их будет недостатком линковщика),


Неверно. И почему недостаток то? Если адрес функции нигде не встречается (ни в сегменте данных, ни в секции кода), то объясните мне каким макаром эта функция может позваться? Откуда? Сделайте простой пример, скомпиляйте _релиз_ версию и все будет понятно.

Насчет виртуальных функций. Они вот как раз всегда будут включаются, потому как адрес на функцию хранится в виртуальной таблице. В принципе и их можно исключать, но для этого уже нужен дополнительный анализ и в рамках линкера эта задача не решаема.
Re[2]: Итог?
От: Аноним  
Дата: 03.09.02 16:30
Оценка:
Здравствуйте Alaxandr, Вы писали:

A>Это я <Аноним>, задавший вопрос.


A>Я думаю, что при компиляции всегда будут включаются ВСЕ описанные мной функции(не включение их будет недостатком линковщика),


Неверно. И почему недостаток то? Если адрес функции нигде не встречается (ни в сегменте данных, ни в секции кода), то объясните мне каким макаром эта функция может позваться? Откуда? Сделайте простой пример, скомпиляйте _релиз_ версию и все будет понятно.

Насчет виртуальных функций. Они вот как раз всегда будут включаются, потому как адрес на функцию хранится в виртуальной таблице. В принципе и их можно исключать, но для этого уже нужен дополнительный анализ и в рамках линкера эта задача не решаема.
Re[3]: Итог?
От: Alaxandr Россия  
Дата: 03.09.02 16:58
Оценка:
Здравствуйте Аноним, Вы писали:

А>Неверно. И почему недостаток то?


А я предлогал оформить вичу как опцию по желанию

А>Если адрес функции нигде не встречается (ни в сегменте данных, ни в секции кода), то объясните мне каким макаром эта функция может позваться? Откуда? Сделайте простой пример, скомпиляйте _релиз_ версию и все будет понятно.


А нефиг хозяйничать без спроса в моем коде!! Может это защита у меня такая — скрытая функция, указатель на которую отдельно

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


Ну и бог с ними...
Re[4]: Итог?
От: Кодт Россия  
Дата: 03.09.02 17:27
Оценка:
Здравствуйте Alaxandr, Вы писали:

А>>Если адрес функции нигде не встречается (ни в сегменте данных, ни в секции кода), то объясните мне каким макаром эта функция может позваться? Откуда? Сделайте простой пример, скомпиляйте _релиз_ версию и все будет понятно.


A>А нефиг хозяйничать без спроса в моем коде!! Может это защита у меня такая — скрытая функция, указатель на которую отдельно


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

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

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


Компилятор должен поддерживать весьма хитрый формат VMT...

A>Ну и бог с ними...
Перекуём баги на фичи!
Re[5]: Итог?
От: Alеxandr Россия  
Дата: 03.09.02 18:11
Оценка:
Здравствуйте Кодт, Вы писали:

К>Если указатель — в том же объектном файле (в той же единице сборки, если компилятор инкрементный), то ситуация вырожденная.

К>Если в другом — то хрен ты до фрагмента кода доступишься, поскольку линкер ничего сделать не сможет.

К>В общем случае, линкер должен строить орграф зависимостей среди единиц сборки.

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

А не надо все за один раза делать: делаем переменную с адресом, компилируем, вычисляем Disassembler-ом точку входа и перезаписываем значение инициализации прямо в EXE-шнике....
Ну, в общем, я думаю это сделать можно, может и не совсем так.
Re[9]: А как убрать переменную?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 04.09.02 04:46
Оценка:
Здравствуйте adb, Вы писали:

adb>А release версию не пробовали собирать?


Да тут дело, наверное, даже не в release опции, а в опции Оптимизация.

Согласен, что в области Линковки я уже не достаточно информирован обо всех тонкостях — всё-таки это не моя область деятельности.

И если есть вопрос для меня, то только о том, почему же неиспользуемая функция может быть не включена в сборку, а неиспользуемая переменная всё равно попадает в сборку?
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.