Я хотел бы видеть все места в своем коде (C++), которые игнорируют возвращаемое значение функции. Как я могу сделать это - с gcc или статическим инструментом анализа кода?
Плохой пример кода:
int f(int z) {
return z + (z*2) + z/3 + z*z + 23;
}
int main()
{
int i = 7;
f(i); ///// <<----- here I disregard the return value
return 1;
}
Обратите внимание на то, что:
Вам нужен атрибут GCC warn_unused_result
:
#define WARN_UNUSED __attribute__((warn_unused_result))
int WARN_UNUSED f(int z) {
return z + (z*2) + z/3 + z*z + 23;
}
int main()
{
int i = 7;
f(i); ///// <<----- here i disregard the return value
return 1;
}
Попытка скомпилировать этот код приводит к:
$ gcc test.c
test.c: In function `main':
test.c:16: warning: ignoring return value of `f', declared with
attribute warn_unused_result
Это видно по использованию в ядре Linux; у них есть __must_check
макрос, который делает то же самое; похоже, чтобы это работало, нужен GCC 3.4 или более поздняя версия. Далее вы увидите этот макрос, используемый в заголовочных файлах ядра:
unsigned long __must_check copy_to_user(void __user *to,
const void *from, unsigned long n);
Два способа:
Для # 1 рассмотрим:
public Expression<Func<Foo, bool>> WhereCreatorIsAdministrator()
{
return f => f.Creator.UserName.Equals("Administrator", StringComparison.OrdinalIgnoreCase);
}
public void DoStuff()
{
var exp = WhereCreatorIsAdministrator();
using (var c = new MyEntities())
{
var q = c.Foos.Where(exp); // supported in L2E
// do stuff
}
}
Пример числа 2: Как составить L2O и L2E запросы . Рассмотрим приведенный здесь пример:
var partialFilter = from p in ctx.People
where p.Address.City == “Sammamish”
select p;
var possibleBuyers = from p in partiallyFilter.AsEnumerable()
where InMarketForAHouse(p);
select p;
Это может быть менее эффективным, или это может быть хорошо. Это зависит от того, что ты делаешь. Обычно это нормально для проекций, часто не подходит для ограничений.
Обновить Только что увидел еще лучшее объяснение опции # 1 от Damien Guard.
-121--3643203-Библиотека журналов Python безопасна для потоков одного процесса.
-121--2910612-Статический анализатор будет вашей лучшей ставкой здесь. Мы используем Coverity здесь, но есть бесплатные инструменты , которые вы также можете использовать.
Если вам нужно быстрое и грязное решение и у вас удобная оболочка в стиле Linux, вы можете попробовать что-то вроде:
grep -rn "function_name" * | grep -v "="
Это найдет каждую строку, которая ссылается на указанную функцию, но не содержит «=». Вы можете получить много ложных срабатываний (и потенциально некоторые ложные негативы), но если у вас нет статического анализатора, это достойное место для начала.
Любой статический код анализа (например, PC-Lint ) должен быть способен сообщить вам об этом. Для PC-Lint, я знаю, что это так.
-121--1051701-Худшая вещь:
Система построения, (да, я знаю, что это не имеет ничего общего с дизайном самого ядра).
Это абсолютный кошмар, ничего подобного никакому другому в существовании, и если по какой-то причине (добавив новую архитектуру, возможно) нужно изменить его, то для этого нужно выучить совершенно новый язык.
Лучше всего:
Почти все можно настроить. Удивительно, что в основном одно и то же ядро используется в крошечных встраиваемых устройствах без MMU и в суперкомпьютерах с огромной памятью и тысячами процессоров.
-121--1266025-статический анализатор будет выполнять работу за вас, но если ваша кодовая база более тривиальная, подготовьтесь к переполнению; -)
Классическая программа 'lint' раньше очень много говорила о функциях, которые возвращали значение, которое игнорировалось. Беда была в том, что многие из этих предупреждений были нежелательными, что приводило к чрезмерному шуму на выходе lint (он улавливал биты пуха, которые вы хотели, чтобы он игнорировал). Вероятно, поэтому в GCC нет стандартного предупреждения.
Другая проблема - обратная сторона - это "как подавить предупреждение, когда вы знаете, что игнорируете результат, но на самом деле вам все равно". Классический сценарий для этого:
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, sighandler);
Вас волнует первый результат из signal()
; вы знаете, что второй будет SIG_IGN (так как вы только что установили его на это). Чтобы отвлечься от предупреждений, я иногда использую какой-то вариант на:
if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
old = signal(SIGHUP, sighandler);
Это присваивает old
оба раза. За этим можно следовать 'assert(old == SIG_IGN)'.
Насколько я знаю, нет варианта GCC, чтобы дать это предупреждение. Однако, если вы заинтересованы в конкретных функциях, вы можете пометить их с атрибутом:
int fn() __attribute__((warn_unused_result));
, который дал бы предупреждение, если возвращаемое значение Fn () не использовалось. Предостережение: я никогда не использовал эту функцию сам.
Вы можете использовать этот удобный шаблон, чтобы сделать это во время выполнения.
Вместо того, чтобы вернуть код ошибки (например, HResult), вы возвращаете return_Code
class return_value
{
public:
explicit return_value(T value)
:value(value), checked(false)
{
}
return_value(const return_value& other)
:value(other.value), checked(other.checked)
{
other.checked = true;
}
return_value& operator=(const return_value& other)
{
if( this != &other )
{
assert(checked);
value = other.value;
checked = other.checked;
other.checked = true;
}
}
~return_value(const return_value& other)
{
assert(checked);
}
T get_value()const {
checked = true;
return value;
}
private:
mutable bool checked;
T value;
};
Любой код статического анализа (например, PC-Lint) должен быть способен это сказать. Для PC-Lint я знаю, что это так.