Как повысить предупреждение, если возвращаемое значение игнорируется?

Я хотел бы видеть все места в своем коде (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;
}

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

  • это должно работать, даже если функция и ее использование находятся в различных файлах
  • свободный статический инструмент проверки
52
задан Matthieu M. 28 October 2016 в 03:59
поделиться

7 ответов

Вам нужен атрибут 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);
54
ответ дан 7 November 2019 в 09:21
поделиться

Два способа:

  1. Методы, которые возвращают выражения могут быть использованы
  2. Разделите запрашиваемые и перечисляемые биты

Для # 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 "="

Это найдет каждую строку, которая ссылается на указанную функцию, но не содержит «=». Вы можете получить много ложных срабатываний (и потенциально некоторые ложные негативы), но если у вас нет статического анализатора, это достойное место для начала.

4
ответ дан 7 November 2019 в 09:21
поделиться

Любой статический код анализа (например, PC-Lint ) должен быть способен сообщить вам об этом. Для PC-Lint, я знаю, что это так.

-121--1051701-

Худшая вещь:

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

Лучше всего:

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

-121--1266025-

статический анализатор будет выполнять работу за вас, но если ваша кодовая база более тривиальная, подготовьтесь к переполнению; -)

4
ответ дан 7 November 2019 в 09:21
поделиться

Классическая программа '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)'.

2
ответ дан 7 November 2019 в 09:21
поделиться

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

int fn() __attribute__((warn_unused_result));

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

10
ответ дан 7 November 2019 в 09:21
поделиться

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

Вместо того, чтобы вернуть код ошибки (например, 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;
};
10
ответ дан 7 November 2019 в 09:21
поделиться

Любой код статического анализа (например, PC-Lint) должен быть способен это сказать. Для PC-Lint я знаю, что это так.

4
ответ дан 7 November 2019 в 09:21
поделиться