LINUX.ORG.RU

[C++] Затратны ли неиспользуемые функции

 


0

0

Рассмотрим такой гипотетический пример: есть программа, состоящая всего из двух файлов: x.h и x.c. Если в этой программе есть 1 000 000 функций, а вызывается из них всего 3 - то после компилляции в итоговом elf-файле окажутся все 1 000 000 или только 3 нужные?

>есть программа, состоящая всего из двух файлов: x.h и x.c.

ну во первых это уже не с++ ;)

Dudraug ★★★★★
()

по идее как мне кажется то все 1 000 000. В библиотеках это разумеется так и есть.

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

Dudraug ★★★★★
()

> Если в этой программе есть 1 000 000 функций

советую не компилировать их с -O3 :)

dilmah ★★★★★
()

Зависит от опций линкера. Можно сделать и так и так.

svu ★★★★★
()

если ничего не путаю, strip поможет. Как я думаю, он этим и занимается и именно поэтому его нельзя на либы натравливать с ключом -s :)

anonymous
()
Ответ на: комментарий от anonymous

> если ничего не путаю, strip поможет. Как я думаю, он этим и занимается

явно путаешь

$ { for i in `seq 1 200000`; do echo 'int foo_'$i'() { int i = '$i'; return i; }'; done; echo 'main() { return foo_666(); }'; } > superproga.c

$ gcc superproga.c

$ ls -la a.out
-rwxr-xr-x 1 dilmah dilmah 8893380 2008-04-20 21:39 a.out

$ strip -s a.out

$ ls -la a.out
-rwxr-xr-x 1 dilmah dilmah 3602860 2008-04-20 21:40 a.out

3 с половиной мега это явно слишком много -- ведь там используются
только 2 простейшие функции: main и foo_666

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

Линуксовый man:
strip - Discard symbols from object files.
-s, --strip-all Remove all symbols.
Солярный:
strip - strip symbol table, debugging and line number infor-
mation from an object file
Что здесь понимается под символом? Неужели неиспользуемая функция?

sergey_feo
() автор топика
Ответ на: комментарий от dilmah

а если собирать с -0s? Я не смог проверить гига оперативы не хватило, ушло в глубокий свой :). Я уверен что gcc сможет собрать мелкий бинарник т.к. он считает какая функция сколько раз запускается.

anonymous
()

> то после компилляции в итоговом elf-файле окажутся все 1 000 000 или только 3 нужные?
если эти функции имеют 'external linkage' (не объявлены как static), то окажутся все 1_000_000. Если 'internal linkage' (объявлены как static) и они не вызываются, и включена оптимизация, то тогда может и не окажутся.

undet
()
Ответ на: комментарий от ilnurathome

Как-то всё это тяжело и ограниченно выглядит:

-ffunction-sections...Only use these options when there are significant benefits from doing so. When you specify these options, the assembler and linker will create larger object and executable files and will also be slower...

--gc-sections...It is ignored on targets that do not support this option. This option is not compatible with ..., nor should it be used with dynamic linking...

Такая простая штука - просто не использовать то, на что нет ссылок - и где-то не поддерживается, что-то будет медленнее, с чем-то там не срастётся... Странно.

sergey_feo
() автор топика
Ответ на: комментарий от sergey_feo

может способ и не лучший, но способ

из примера dilmah, удалось вырезать все лишнее, только число функций лучше уменьшить до 20000, а то всю память отъедает при компиляции и линковке

$ { for i in `seq 1 20000`; do echo 'int foo_'$i'() { int i = '$i'; return i; }'; done; echo 'main() { return foo_666(); }'; } > superproga.c

$ gcc superproga.c

$ ls -s a.out
864 a.out

$ gcc superproga.c -ffunction-sections -Wl,--gc-sections

$ ls -s a.out
12 a.out

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

Видоизменим пример
$ { for i in `seq 1 20000`; do echo 'int foo_'$i'() { int i = '$i'; return i; }'; done; echo 'main() { int (*f1)()=foo_1; int (*f2)()=foo_2; printf("1 - %p returned %i\n", f1, f1()); printf("2 - %p returned %i\n", f2, f2()); '; for i in `seq 3 2000`; do echo 'int (*f'$i')()=f1+(f2-f1)*('$i'-1); printf("%d - %p returned %d\n", '$i', f'$i', f'$i'() );'; done; echo 'return foo_666(); }'; } > superproga3.c

$ gcc superproga3.c -ffunction-sections -Wl,--gc-sections -o super3
$ gcc superproga3.c -ffunction-sections -o super3_n

и в этой ситуации прога без использования сборщика мусора выводит нормальный вывод
$ super3_n
1 - 0x80483c4 returned 1
2 - 0x80483d6 returned 2
3 - 0x80483e8 returned 3
4 - 0x80483fa returned 4
5 - 0x804840c returned 5
6 - 0x804841e returned 6
и т.д.

а прога после использования мусора сборщика выводит совсем не то
$ super3
1 - 0x80483a3 returned 1
2 - 0x80483b5 returned 2
3 - 0x80483c7 returned 666
1 - 0x80483a3 returned 1
2 - 0x80483b5 returned 2
3 - 0x80483c7 returned 666
Сборщик мусора, не увидев неявного использования функций, оставил только использованные явно func_1 func_2 func_666

ilnurathome
()
Ответ на: комментарий от ilnurathome

правда в C++ на конструкцию вида

int (*f3)()=f1+(f2-f1)*(3-1);

По идее должен обматерить программиста, но кто нам помешает указать адрес на функцию явно через приведение типов типа:

int (*f2000)()=(int (*)())0x8051112;

или еще каким способом.

Если в проге возможно применение указателей сделать сборщик мусора совсем не тривиально, если вообще возможно.

ilnurathome
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.