exponenta event banner

Количество рекурсий

Количество циклов графика вызовов в одной или нескольких функциях

Описание

В метрике представлена количественная оценка количества циклов рекурсии в проекте. Метрика представляет собой сумму:

  • Количество прямых рекурсий (саморекурсивных функций или функций, вызывающих себя).

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

    Для вычисления количества сильно связанных компонентов:

    1. Нарисуйте циклы рекурсии в коде.

      Например, циклы рекурсии в этом примере показаны ниже.

      volatile int checkStatus;
      void func1() {
         if(checkStatus) {
              func2();
         }
         else {
              func3();
         }
      }
      
      func2() {
         func1();
      }
      
      func3() {
         func1();
      }

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

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

      В списке событий под метрикой показан один из циклов рекурсии в сильно связанном компоненте.

Вызовы через указатель функции не рассматриваются.

Рекомендуемый верхний предел для этой метрики равен 0. Чтобы избежать возможности превышения доступного пространства стека, не используйте рекурсии в коде. Рекурсии могут иметь тенденцию к легкому исчерпанию пространства стека. См. примеры увеличения размера стека с помощью рекурсий, описанных для этого правила CERT-C, запрещающего рекурсии.

Для выявления использования рекурсий проверьте наличие нарушений одной из MISRA C:2012 Rule 17.2, MISRA C ®: 2004 Правило 16.2,MISRA C++:2008 Rule 7-5-4 или JSF ® Rule 119. Обратите внимание, что :

  • Проверки правил сообщают о каждой функции, которая вызывает себя, прямо или косвенно. Даже если в одном цикле рекурсии задействовано несколько функций, каждая функция сообщается отдельно.

  • Средства проверки правил рассматривают только явные вызовы функций. Например, в коде C++ средства проверки правил игнорируют неявные вызовы конструкторов во время создания объекта. Однако при вычислении метрик учитываются как неявные, так и явные вызовы.

Сведения о наложении ограничений на метрики см. в разделе Метрики сложности вычислительного кода.

Примеры

развернуть все

int getVal(void);
int sum(int val) {
    if(val<0)
        return 0;
    else
        return (val + sum(val-1));
}

void main() {
    int count = getVal(), total;
    assert(count > 0 && count <100);
    total = sum(count);
}

В этом примере число рекурсий равно 1.

Прямая рекурсия - это рекурсия, в которой функция вызывает себя в собственном теле. Для прямых рекурсий число рекурсий равно числу рекурсивных функций.

volatile int signal;
void operation2(void);

void operation1(void) {
    int stop = signal%2;
    if(!stop)
        operation2();
}

void operation2(void) {
    operation1();
}

void main() {
    operation1();
}

В этом примере число рекурсий равно единице. Две функции operation1 и operation2 участвуют в цикле графа вызовов operation1operation2operation1.

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


volatile int checkStatus;
void func1() {
   if(checkStatus) {
        func2();
   }
   else {
        func3();
   }
}

func2() {
   func1();
}

func3() {
   func1();
}

В этом примере существует два цикла графа вызовов:

  • func1func2func1

  • func1func3func1

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

volatile int signal;
void operation1_1();
void operation2_1();

void operation1() {
    int stop = signal%2;
    if(!stop)
        operation1_1();
}


void operation1_1() {
    operation1();
}

void operation2() {
    int stop = signal%2;
    if(!stop)
        operation2_1();
}

void operation2_1() {
    operation2();
}

void main(){
    operation1();
    operation2();
}

В этом примере число рекурсий равно двум.

Существует два цикла графов вызовов:

  • operation1operation1_1operation1

  • operation2operation2_1operation2

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

volatile int signal;
void operation2();

void operation1() {
    int stop = signal%3;
    if(stop==1)
        operation1();
    else if(stop==2)
        operation2();
}

void operation2() {
    operation1();
}

void main() {
    operation1();
}

В этом примере число рекурсий равно двум:

  • Сильно связанный компонент, образованный циклом operation1operation2operation1.

  • Самрекурсивная функция operation1.

Метрическая информация

Группа: Проект
Акроним: AP_CG_CYCLE
ЕГО метрика: Да