Есть ли способ идентифицировать все неиспользуемые глобальные переменные в C-проекте? - PullRequest
8 голосов
/ 31 октября 2011

Я чищу немного кода Си.Везде есть глобальные переменные, но не все они используются.Я хочу очистить их.Но это слишком много работы, чтобы проверить их по одному.Есть ли простой способ сделать это?

Ответы [ 6 ]

6 голосов
/ 31 октября 2011

Вы можете создать список всех глобальных переменных в вашем каталоге, используя очень полезную команду ctags(1) с параметром командной строки -x:

ctags  -x  --c-kinds=v  --file-scope=no *.c

Это можно комбинировать с полезной командой gid(1) (при условии, что вы сначала запустили mkid(1) в своих источниках):

for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done

Это дает вам полезный список того, какие файлы используют какие глобальные:

$ for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done
basedir        parser.h ./{parser_include,parser_main}.c
binary_input   parser_main.c
cache_fd       parser.h ./{parser_interface,parser_main}.c
conf_quiet     parser.h parser_main.c
conf_verbose   parser.h ./{parser_interface,parser_main}.c
...

Это не идеально (как Ира указывает ), но это должно быть хорошее начало.

3 голосов
/ 31 октября 2011

Этот ответ относится к исходному вопросу. Впоследствии вопрос был изменен.

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

Правдивая история. Программист, который останется безымянным, удалил «неиспользуемый» глобал из производственного приложения. К сожалению, конструктор для этой глобальной выделенной памяти из распределителя, который инициализируется при первом выделении.

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

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

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

3 голосов
/ 31 октября 2011

Если они используются только внутри файла, вы можете объявить их "статическими", и GCC предупредит, если они никогда не используются.

Если они используются из нескольких файлов ... Я не уверенкак вы могли бы обнаружить это, кроме поиска или использования IDE, потому что они будут отображаться как символы компоновщика и теоретически могут быть доступны для любого кода, связывающегося с вашим кодом ...

2 голосов
/ 31 октября 2011

Легко?Нет. Для глобальной переменной X вам нужно отсканировать каждую единицу компиляции в вашем коде для потенциального доступа к X (чтение, запись или генерация ссылки).Если таких обращений нет, то вы можете быть достаточно уверены (у вас нет ассемблерного кода, верно?), Что X не используется.

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

1 голос
/ 31 октября 2011

(@ ChrisLutz опубликовал эту идею как комментарий, но я подумал об этом, прежде чем прочесть комментарий, поэтому я все равно опубликую его. Я постараюсь добавить некоторую ценность, расширив его.)

В отдельной копии вашего исходного кода закомментируйте объявления всех ваших глобальных переменных и перекомпилируйте все.Сравните список переменных, которые вы закомментировали, с упомянутыми в сообщениях об ошибках компилятора.Все, что не упомянуто в сообщении об ошибке, не используется.

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

Немного другойПодход, позволяющий избежать этой проблемы, является итеративным: закомментируйте все ваши глобальные переменные, попробуйте создать, а затем раскомментируйте объявления для всего, на что жаловался компилятор.Повторяйте, пока не получите чистую сборку, и посмотрите, что еще закомментировано.

0 голосов
/ 31 октября 2011

Doxygen может дать вам список вариантов использования глобальных переменных.

...