неиспользуемые функции `stati c inline` генерируют предупреждения с помощью` clang` - PullRequest
1 голос
/ 29 января 2020

При использовании gcc или clang обычно рекомендуется включить несколько предупреждений, а первая партия предупреждений обычно предоставляется -Wall. Этот пакет довольно большой и включает в себя заданное c предупреждение -Wunused-function.

Теперь -Wunused-function полезно для обнаружения static функций, которые больше не вызываются, то есть они бесполезны и должны поэтому желательно удалить из исходного кода. При применении политики «нулевого предупреждения» она больше не «предпочтительна», но совершенно обязательна.

Из соображений производительности некоторые функции могут быть определены непосредственно в заголовочных файлах *.h, чтобы их можно было встроить во время компиляции (не учитывая магию LTO c). Такие функции обычно объявляются и определяются как static inline. В прошлом такие функции, вероятно, вместо этого можно было бы определять как макросы, но было бы лучше сделать их static inline функциями вместо этого, когда это применимо (без смешных проблем с типами).

ОК, так что теперь у нас есть множество функций, определенных непосредственно в заголовочные файлы, по соображениям производительности. Блок, включающий такой заголовочный файл, не обязан использовать все свои объявленные символы. Следовательно, функция static inline, определенная в заголовочном файле, может не вызываться.

Для gcc это нормально. gcc будет обозначать неиспользуемую static функцию, но не inline static. Для clang, однако, результат будет другим: функции static inline, объявленные в заголовках, вызывают предупреждение -Wunused-function, если один модуль не вызывает их. И для этого не нужно много флагов: достаточно -Wall.

Обходное решение - ввести расширение c, определяемое компилятором, такое как __attribute__((unused)), которое явно заявляет компилятору, что функция, определенная в заголовке, не обязательно вызывается всеми ее модулями. Хорошо, но теперь код, который раньше был чистым C99, включает некоторую форму специфического расширения компилятора c, добавляя вес переносимости и обслуживания.

Поэтому вопрос больше о логике c такого выбора: почему clang выбирает для запуска предупреждения, когда не вызывается функция static inline, определенная в заголовке? В каком случае это хорошая идея?

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

edit : После дальнейшего исследования выясняется, что вопрос неверен. Предупреждение вызывается в редакторе (VSCode) с использованием clang linter с применением выбранных флагов компиляции списка (-Wall, et c.). Но когда исходный код фактически скомпилирован с clang и с точно таким же списком флагов, предупреждение «неиспользуемая функция» отсутствует.

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

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


Обратите внимание на комментарий :

ОК, извините, это на самом деле отличается от ожидания , Похоже, что предупреждение вызывается в редакторе с использованием clang linter с выбранными флагами компиляции (-Wall, et c.). Но когда исходный код скомпилирован с точно такими же флагами, предупреждение «неиспользуемая функция» фактически отсутствует. До сих пор результаты, видимые в редакторе, были точно такими же, какие были найдены во время компиляции; это первый раз, когда я вижу разницу. Таким образом, проблема, похоже, связана с тем, как линтер использует clang для создания своего списка предупреждений. Кажется, это более сложный вопрос [чем я понял].

Ответы [ 3 ]

1 голос
/ 29 января 2020

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

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

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

0 голосов
/ 29 января 2020

При использовании gcc или clang обычно рекомендуется включить несколько предупреждений,

При использовании любого C компилятора Хорошая идея - убедиться, что уровень предупреждений увеличен, и обратить внимание на полученные предупреждения. Таким образом можно избежать многих поломок, путаницы и напрасных усилий.

Теперь -Wunused-function полезен для обнаружения static функций, которые больше не вызываются, то есть они бесполезны, и поэтому должны желательно удалить из исходного кода. При применении политики «нулевого предупреждения» она больше не «предпочтительна», но совершенно обязательна.

Обратите внимание, что

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

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

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

По соображениям производительности некоторые функции могут быть определены непосредственно в заголовочных файлах *.h, так что они могут быть встроены во время компиляции (без учета LTO magi c).

Это выбор. Чаще всего это дает небольшое преимущество.

Такие функции обычно объявляются и определяются как static inline. В прошлом такие функции, вероятно, вместо этого определяли бы как макросы, но считается, что вместо них лучше сделать их static inline функциями, когда это применимо (без смешных проблем с типами).

Кто и как рассматривал? Есть причины отдавать предпочтение функциям над макросами, но в некоторых случаях есть причины отдавать предпочтение макросам. Не все такие причины объективны.

Подразделение, включающее такой заголовочный файл, не обязано использовать все свои объявленные символы.

Правильно.

Следовательно, встроенная функция stati c, определенная в заголовочном файле, не может быть разумно вызвана.

Ну, это вопрос того, что человек считает "разумным". Одно дело иметь причины хотеть делать что-то таким образом, но перевешивают ли эти причины те, что не делают этого так, - это суждение. Я не будет этого делать.

Поэтому вопрос больше касается логики c такого выбора: почему Clang выбирает, чтобы вызвать предупреждение, когда состояние c встроенная функция, определенная в заголовке, не вызывается? В каком случае это хорошая идея?

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

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

И что предлагает Clang, чтобы охватить относительно распространенный случай встроенных функций, определенных в заголовочном файле, без запроса использования компилятора extension?

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

С учетом сказанного вы можете попытаться определить функции в заголовке как extern inline вместо static inline. Затем вы обязаны предоставить одно не встроенное определение каждого где-то во всей программе, но в противном случае оно может быть лексически идентичным встроенным определениям. Я предполагаю, что это может успокоить Clang.

0 голосов
/ 29 января 2020

'# ifdef USES_FUNTION_XYZ'

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

...