GBS Logo HELP HOME Generic Build Support (GBS) - User Manual
Metrics Help Bottom Doc. Button
Release RMC-06.02
(2024-04-29)


- Home
Getting Started
- Quick Start
- Release Notes
- Install Notes
- Create a GBS-WA/System
- FAQ
- Terms and Conditions (The Fine Print)
Basics
- Definitions & Acronyms
- Introduction
- Top Level Directory Structure
- Full Directory Structure
- Handling SubSystems & Steps
- Procedures
- Software Configuration Management Support

Manual Pages
- The Command-Line Interface
- All Commands
- The gbssys... Commands
- Generating Code (Building)
- Libraries & Executables and Testing
- Exporting Deliverables
- Auditing
- Customisations (Session)
- Customisations (User)
- Customisations (Admin)
- Integration with other Tools
- Plugins (Admin)
- Environment Variables (EnvVars)
User Files
- The GLKBT (glk/glb/glt) Files
Internal (.gbs) Files
- GBS Files - General
- audit.gbs
- broadcast.gbs
- build.gbs
- export.gbs
- flags_*.gbs
- subsys.gbs (.bat/.sh)
- incs_*.gbs
- owners.gbs
- sca_*.gbs
- scope.gbs
- site.gbs (.bat/.sh)
- steps.gbs
- switch.gbs (.bat/.sh)
- system.gbs
- tool.gbs
Various
- Development
- About
- Metrics Help

Full Documentation
- All Docs - Printable


Contents Bottom Doc. Button Top Document Button Down Section Button Blank

Metrics Overview
Function-Based Metrics
File-Based Metrics
Class-Based Metrics
Project-Wide Metrics
General

Metrics Overview Bottom Doc. Button Top Document Button Down Section Button Up Section Button

The Calculation of Metrics Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

QAC calculates metrics in three groups.
Function metrics are generated for all functions with a full definition.
File metrics are generated for each file analyzed.
Project metrics are calculated once per complete project, and are generated from cross-module analysis.

QAC++ calculates metrics in three groups.
Function metrics are generated for all functions with a full definition.
Class metrics are generated for each defined class.
File metrics are generated for each file analyzed.

All metrics, except LIN and TPP, ignore code that is disabled on evaluation of pre-processor directives.
That is, both the code in the source file and the #include'd files inside conditional pre-processor directives are ignored for all metrics except LIN and TPP.

For example:

    
        #define A 10
        #if 0
        #include <stdio.h>      /* Ignored by all except LIN, TPP */
        int i;                  /* Ignored by all except LIN, TPP */
        #else
        long i;
        #endif
    

Function-Based Metrics Overview Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

These metrics are all calculated for the source code of an individual function. Some metrics are used in the definition of others, but there is no obvious sequence. They are described here in alphabetical order, for ease of reference. The complete list is as follows:

AKIAkiyama's Criterion
AV1Average Size of Statement in Function (variant 1)
AV2Average Size of Statement in Function (variant 2)
AV3Average Size of Statement in Function (variant 3)
BAKNumber of Backward Jumps
CALNumber of Functions Called from Function
CYCCyclomatic Complexity
ELFNumber of Dangling Else-Ifs
FN1Number of Operator Occurrences in Function
FN2Number of Operand Occurrences in Function
GTONumber of Goto statements
HLBNumber of Halstead's delivered bugs (B)
KDNKnot Density
KNTKnot Count
LCTNumber of Local Variables Declared
LINNumber of Code Lines
LOPNumber of Logical Operators
M07Essential Cyclomatic Complexity
M19Number of Exit Points
M29Number of Functions Calling this Function
MCCMyer's Interval
MIFDeepest Level of Nesting
PARNumber of Function Parameters
PBGResidual Bugs (PTH-based est.)
PDNPath Density
PTHEstimated Static Program Paths
RETNumber of Return Points in Function
ST1Number of Statements in Function (variant 1)
ST2Number of Statements in Function (variant 2)
ST3Number of Statements in Function (variant 3)
SUBNumber of Function Calls
UNRNumber of Unreachable Statements
UNVUnused or Non-Reused Variables
XLNNumber of Executable Lines

File-Based Metrics Overview Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

These metrics are all calculated for the source code in a complete translation unit (TU). They are listed alphabetically here for convenience. They are not calculated in this sequence. because of their derivation from each other:

BMEEmbedded Programmer Months
BMOOrganic Programmer Months
BMSSemi-detached Programmer Months
BUGResidual Bugs (token-based estimate)
CDNComment to Code Ratio
DEVEstimated Development (programmer-days)
DIFProgram Difficulty
ECTNumber of External Variables Declared
EFFProgram Effort
FCOEstimated Function Coupling
FNCNumber of Functions in File
HALHalstead Prediction of TOT
M20Number of Operand Occurrences
M21Number of Operator Occurrences
M22Number of Statements
M28Number of Non-Header Comments
M33Number of Internal Comments
OPNNumber of Distinct Operands
OPTNumber of Distinct Operators
SCTNumber of Static Variables Declared
SHNShannon Information Content
TDEEmbedded Total Months
TDOOrganic Total Months
TDSSemi-detached Total Months
TLNTotal Preprocessed Source Lines
TOTTotal Number of Tokens Used
TPPTotal Unpreprocessed Code Lines
VARTotal Number of Variables
VOLProgram Volume
ZIPZipf Prediction of TOT
  
CCATotal Number of Characters
CCBTotal Number of Code Characters
CCCTotal Number of Comment Characters

Class-Based Metrics Overview Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

These metrics are calculated for the classes in your source code. To calculate some of these metrics you must also have run the relevant cross-module analysis program. See Cross-Module Analysis in Chapter 4: Analysing Source Code. Class-based metrics are described here in alphabetical order for ease of reference:

CBOCoupling between objects
DITDeepest level of inheritance
LCMLack of cohesion of methods within a class
MTHNumber of methods available in class
NOCNumber of immediate children
NOPNumber of immediate parents
RFCResponse for class
WMCWeighted methods per class

Project-Wide Metrics Overview Bottom Doc. Button Top Document Button Down Section Button Up Section Button Blank Up Chapter Button

These metrics are calculated once per complete project. The complete list is as follows:

NRANumber of Recursions Across Project
NEANumber of Entry Points Across Project
NFANumber of Functions Across Project
CYACyclomatic Complexity Across Project

Function-Based Metrics Bottom Doc. Button Top Document Button Down Section Button Up Section Button

AKI - Akiyama's Criterion Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

Function-Based Metric

This metric is the sum of the Cyclomatic complexity (CYC) and the number of function calls (SUB). Although this is not an independent metric, it is included on account of its use in documented case histories. See Akiyama[1] and Shooman[2] for more details. The metric is calculated as:

AKI = CYC + SUB

[1] Akiyama, F. (1971) An Example of Software System Debugging, Proc. IFIP Congress 1971, Lbujlana, Yugoslavia, American Federation of information Processing Societies, Montvale, New Jersey.

[2] Shooman, M.L. (1983) Software Engineering, McGraw-Hill, Singapore.

AV1 - Average Size of Statement in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

AV2 - Average Size of Statement in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

AV3 - Average Size of Statement in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

AVx - Average Size of Statement in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metrics

These metrics (AV1, AV2, and AV3) measure the average number of operands and operators per statement in the body of the function. They are calculated using Halstead's[1] calculations as follows:

AVx = (N1 + N2) / number of statements in the function

where:
N1 is Halstead's number of operator occurrences.
N2 is Halstead's number of operand occurrences.

The AVx metrics are computed using ST1, ST2 and ST3 to represent the number of statements in a function. Hence there are three variants: AV1, AV2 and AV3 relating to the respective statement count metrics.

This metric is used to detect components with long statements. Statements comprising a large number of textual elements (operators and operands) require more effort by the reader in order to understand them. This metric is a good indicator of the program's readability.

Metric values are computed as follows:

AV1 = (FN1 + FN2) / ST1
AV2 = (FN1 + FN2) / ST2
AV3 = (FN1 + FN2) / ST3

[1] Halstead, Maurice H. (1977). Elements of Software Science.

BAK - Number of Backward Jumps Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

Jumps are never recommended and backward jumps are particularly undesirable. If possible, the code should be redesigned to use structured control constructs such as while or for instead of goto.

Example

        main()
        {
        Backward:
    	switch (n)
    	{
    	case 0:
    	    printf( stdout, "zero\n");
    	    break;
    	case 1:
    	    printf( stdout, "one\n");
    	    goto Backward;                  /* 1 */
    	    break;
    	case 2:
    	    printf( stdout, "two\n");
    	    break;
    	default: printf( stdout, "many\n");
    	    break;
    	}
        }
    

The above code sample has a BAK value of 1.

CAL - Number of Functions Called from Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric counts the number of function calls in a function.

It differs from the metric SUB, in that only distinct functions are counted (multiple instances of calls to a particular function are counted as one call), and also that functions called via pointers are not counted.

CYC - Cyclomatic Complexity Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

Cyclomatic complexity is calculated as the number of decisions plus 1.

High cyclomatic complexity indicates inadequate modularization or too much logic in one function. Software metric research has indicated that functions with a cyclomatic complexity greater than 10 tend to have problems related to their complexity.

McCabe[1] gives an essential discussion of this issue as well as introducing the metric.

Example 1

        int divide( int x, int y)
        {
    	if (y != 0)                     /* 1 */
    	{
    	    return x / y;
    	} else if (x == 0)              /* 2 */
    	{
    	    return 1;
    	} else
    	{
    	    printf( "div by zero\n");
    	    return 0;
    	}
        }
    

The above code sample has a cyclomatic complexity of 3 as there are two decisions made by the function. Note that correctly-indented code does not always reflect the nesting structure of the code. In particular, the use of the construct 'else if' always increases the level of nesting, but it is conventionally written without additional indentation and so the nesting is not visually apparent.

Example 2

        void how_many(int n)
        {
    	switch (n)
    	{
    	case 0:
    	    printf( "zero");            /* 1 */
    	    break;
    	case 1:
    	    printf( "one");             /* 2 */
    	    break;
    	case 2:
    	    printf( "two");             /* 3 */
    	    break;
    	default:
    	    printf( "many");
    	    break;
    	}
        }
    

The above code sample has a cyclomatic complexity of 4, as a switch statement is equivalent to a series of decisions.

Some metrication tools include use of the ternary operator ? : when calculating cyclomatic complexity. It could also be argued that use of the && and || operators should be included. Instead, CYC calculation is based on statements alone.

CYC is one of the three standard metrics used by QAC for demographic analysis.

[1] McCabe, T. J. (1976) A Complexity Measure, IEEE Transactions on Software Engineering, SE-2, pp. 308-320.

ELF - Number of Dangling Else-Ifs Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the number of if-else-if constructs that do not end in an else clause. This metric is calculated by counting all if statements that do not have a corresponding else and for which QAC issues a warning 2004. ELF provides a quick reference allowing monitoring of these warnings. The code sample below has an ELF value of 1.

Example

        int divide(int x, int y)
        {
    	if (y != 0)
    	{
    	    return x/y;
    	} else if (x == 0)
    	{
    	    return 1;
    	}
        }
    

FN1 - Number of Operator Occurrences in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is Halstead's[1] operator count on a function basis (N1). FN1 is related to OPT and M21: all of these metrics count 'operators', the difference is summarized as:

FN1Counts ALL operators in the function body
M21Counts ALL operators in the file
OPTCounts DISTINCT operators in the file

See OPT for the definition of an operator.

[1] Halstead, Maurice H. (1977). Elements of Software Science.

FN2 - Number of Operand Occurrences in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is Halstead's[1] operand count on a function basis (N2). FN2 is related to OPN and M20: all of these metrics count 'operands', the difference is summarized as:

FN2Counts ALL operands in the function body
M20Counts ALL operands in the file
OPNCounts DISTINCT operands in the file

See OPN for the definition of an operand.

[1] Halstead, Maurice H. (1977). Elements of Software Science.

GTO - Number of Goto statements Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

Some occurrences of goto simplify error handling. However, they should be avoided whenever possible. According to the Plum Hall Guidelines, goto should not be used.

HLB - Number of Halstead's delivered bugs (B) Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

The metric is an estimate for the number of errors in the implementation.
High values of Halstead's[1] delivered bugs (B) metrics indicate possibility of high number of bugs.
The value of this metric is highly correlated to the size of a function.

The metric is defined in following way:
B = V / 3000

where:

Function Volume V = N * log2(n)
N - the number of all operators and operands within function
n - the number of distinct operators and operands within function

Example

        int foo( int i)     /* Violation: B = 0.09 */
        {
    	int a;
    	int b;
    
    	a = i + (2 * (i + 1)) + (3 * (i + 2));
    	b = (i + (2 * (i + 1)) + (3 * (i + 2))) * 2;
    
    	if (i >= 3)
    	    return a;
    	if (i >= 2)
    	    return b;
        }
    

[1] Halstead, Maurice H. (1977). Elements of Software Science.

KDN - Knot Density Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the number of knots per executable line of code. The metric is calculated as:

KDN = KNT / XLN

The value is computed as zero when XLN is zero.

KNT - Knot Count Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the number of knots in a function. A knot is a crossing of control structures, caused by an explicit jump out of a control structure either by break, continue, goto, or return. KNT is undefined for functions with unreachable code.

This metric measures knots, not by counting control structure crossings, but by counting the following keywords:

  • goto statements,
  • continue statements within loop statements
  • break statements within loop or switch statements, except those at top switch level,
  • all return statements except those at top function level.

The function below has an KNT value of 1.

Example

        void fn( int n, int array[], int key )
        {
    	while ( array[ n ] != key )
    	{
    	    if ( array[ n ] == 999 )
    	    {
    		break;
    	    } else
    	    {
    		++n;
    	    }
    	}
        }
    

LCT - Number of Local Variables Declared Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the number of local variables of storage class auto, register, or static declared in a function. These are variables that have no linkage. The function below has an LCT value of 2.

Example

        int other_result;
        extern int result;
    
        int test()
        {
    	int x;                                  /* 1 */
    	int y;                                  /* 2 */
    
    	return (x + y + other_result);
        }
    

LIN - Number of Code Lines Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the total number of lines, including blank and comment lines, in a function definition between (but excluding) the opening and closing brace of the function body. It is computed on raw code. LIN is undefined for functions which have #include'd code or macros which include braces in their definition.

The function below has an LIN value of 5.

Example

        int fn()
        {
    	int x;                  /* 1 */
    	int y;                  /* 2 */
    				/* 3 */
    	return (x + y);         /* 4 */
    	/* Comment Here */      /* 5 */
        }
    

Long functions are difficult to read, as they do not fit on one screen or one listing page. An upper limit of 200 is recommended.

LOP - Number of Logical Operators Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the total number of logical operators (&&, ||) in the conditions of do-while, for, if, switch, or while statements in a function. The example function below has a LOP value of 2.

Example

        void fn( int n, int array[], int key )
        {
    	while (( array[n] != key ) && ( n > 0 ))
    	{
    	    if (( array[n] == 999) || ( array[n] == 1000 ))
    	    {
    		break;
    	    } else
    	    {
    		++n;
    	    }
    	}
        }
    

M07 - Essential Cyclomatic Complexity Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

The essential cyclomatic complexity is obtained in the same way as the cyclomatic complexity but is based on a 'reduced' control flow graph. The purpose of reducing a graph is to check that the component complies with the rules of structured programming.

A control graph that can be reduced to a graph whose cyclomatic complexity is 1 is said to be structured. Otherwise reduction will show elements of the control graph which do not comply with the rules of structured programming.

The principle of control graph reduction is to simplify the most deeply nested control subgraphs into a single reduced subgraph. A subgraph is a sequence of nodes on the control flow graph which has only one entry and exit point. Four cases are identified by McCabe[1] which result in an unstructured control graph. These are:

  • a branch into a decision structure,
  • a branch from inside a decision structure,
  • a branch into a loop structure,
  • a branch from inside a loop structure.

However, if a subgraph possesses multiple entry or exit points then it cannot be reduced. The use of multiple entry and exit points breaks the most fundamental rule of structured programming.

The example below has a M07 value of 4.

Example

        void g( int n, int pos, int force )  /* M07 = 4
    					    Cannot reduce control graph to
    					    Cyclomatic Complexity of 1 */
        {
    	int nlines = 0;
    
    	while ( --n >= 0 )
    	{
    	    pos = back_line( pos );
    	    if ( pos == 0 )
    	    {
    		if ( ! force )
    		{
    		    break;
    		}
    		++nlines;
    	    }
    	}
        }
    

[1] McCabe, T. J. (1976) A Complexity Measure, IEEE Transactions on Software Engineering, SE-2, pp. 308-320.

M19 - Number of Exit Points Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a measure of the number of exit points in a software component and is calculated by counting the number of return statements. A function that has no return statements will have an M19 value of zero even though it will exit when falling through the last statement. This is regardless of whether the function is declared to have a return value or not (i.e. returns void). Calls to non-returning functions such as exit() or abort() are ignored by this metric.

The example below has an M19 value of 3.

Example

        void f( int a )
        {
    	return;             /* 1 */
    	if ( a )
    	    return;         /* 2 */
    	a++;
    	return;             /* 3 */
        }
    

M29 - Number of Functions Calling this Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is defined as the number of functions calling the designated function. The number of calls to a function is an indicator of criticality. The more a function is called, the more critical it is and, therefore, the more reliable it should be.

MCC - Myer's Interval Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is an extension to the cyclomatic complexity metric. It is expressed as a pair of numbers, conventionally separated by a colon. Myer's Interval is defined as CYC : CYC + L

Cyclomatic complexity (CYC) is a measure of the number of decisions in the control flow of a function. L is the value of the QAC LOP metric which is a measure of the number of logical operators (&&, ||) in the conditional expressions of a function. A high value of L indicates that there are many compound decisions, which makes the code more difficult to understand. A Myer's interval of 10 is considered very high.

The example below has a MCC value of 3:4 because the cyclomatic complexity is 3 and there is one connective (&&) used in the conditions.

Example

        int divide( int x, int y)
        {
    	if (y != 0)                     /* Condition 1 */
    	{
    	    return x / y;
    	} else if (x == 0 && y > 2)     /* Condition 2 */
    					/* Conditional expr 1 */
    	{
    	    return 1;
    	} else
    	{
    	    printf( "div by zero\n");
    	    return 0;
    	}
        }
    

Note:

In the calculation of MCC, the ternary operator (?:) is ignored.

When exporting metric values or displaying in the Metrics Browser, rather than attempting to display a value pair, the value of L is chosen for MCC.

MIF - Deepest Level of Nesting Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a measure of the maximum control flow nesting in your source code.

You can reduce the value of this metric by turning your nesting into separate functions. This will improve the readability of the code by reducing both the nesting and the average cyclomatic complexity per function.

The code example below has an MIF value of 3.

Example

        int divide( int x, int y)
        {
    	if (y != 0)                         /* 1 */
    	{
    	    return (x/y);
    	} else if (x == 0)                  /* 2 */
    	{
    	    return 1;
    	} else
    	{
    	    printf( "Divide by zero\n");
    	    while (x > 1)                   /* 3 */
    		printf( "x = %i", x);
    	    return 0;
    	}
        }
    

MIF is incremented in switch, do, while, if and for statements. The nesting level of code is not always visually apparent from the indentation of the code. In particular, an else if construct increases the level of nesting in the control flow structure but is conventionally written without additional indentation.

MIF is one of the three standard metrics used by QAC for demographic analysis.

PAR - Number of Function Parameters Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric counts the number of declared parameters in the function argument list. Note that ellipsis parameters are ignored.

PBG - Residual Bugs (PTH-based est.) Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

Hopkins, in Hatton & Hopkins[1] investigated software with a known audit history and observed a correlation between Static Path Count (PTH) and the number of bugs that had been found. This relationship is expressed as PBG.

PBG = log10 ( PTH )

[1] Hatton, L., Hopkins, T.R., (1989) Experiences With Flint, a Software Metrication Tool for Fortran 77, Symposium on Software Tools, Napier Polytechnic, Edinburgh, Scotland.

PDN - Path Density Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is a measure of the number of paths relative to the number of executable lines of code.

PDN = PTH / XLN
PDN is computed as zero when XLN is zero.

PTH - Estimated Static Program Paths Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is similar to Nejmeh's[1] NPATH statistic and gives an upper bound on the number of possible paths in the control flow of a function. It is the number of non-cyclic execution paths in a function.

The NPATH value for a sequence of statements at the same nesting level is the product of the NPATH values for each statement and for the nested structures. NPATH is the product of:

  • NPATH( sequence of non control statements ) = 1
  • NPATH(if) = NPATH(body of then) + NPATH( body of else)
  • NPATH(while) = NPATH( body of while) + 1
  • NPATH(do while) = NPATH(body of while) + 1
  • NPATH(for) = NPATH(body of for) + 1
  • NPATH(switch) = Sum( NPATH(body of case 1) ... NPATH(body of case n) )

Note:

else and default are counted whether they are present or not.

In switch statements, multiple case options on the same branch of the switch statement body are counted once for each independent branch only. For example:

Example

        switch( n )
        {
        case 0:
    	break;          /* NPATH of this branch is 1                */
        case 1:
        case 2:
    	break;          /* NPATH for case 1 &amp; case 2 combined is 1  */
        default:
    	break;          /* NPATH for this default is 1              */
        }
    

Since NPATH cannot be reliably computed if there are goto statements in the function, they are ignored by QAC for the purposes of calculating NPATH.

The following code example has a static path count of 26.

Example

        int n;
        if ( n )
        {
        } /* block 1, paths 1 */
        else if ( n )
        {
    	if ( n )
    	{
    	} /* block 2, paths 1 */
    
    	else
    	{
    	} /* block 3, paths 1 */
    
    	/* block 4, paths block2+block3 = 2 */
    
    	switch ( n )
    	{
    	case 1 : break;
    	case 2 : break;
    	case 3 : break;
    	case 4 : break;
    	default: break;
    	} /* block 5, paths = 5 */
    
        } /* block 6, paths block4*block5 = 10 */
        else
        {
    	if ( n )
    	{
    	} /* block 7, paths 1 */
    
    	else
    	{
    	} /* block 8, paths 1 */
        } /* block 9, paths block7+block8 = 2 */
        /* block 10, paths block1+block6+block9 = 13 */
    
        if ( n )
        {
        } /* block 11, paths 1 */
    
        else
        {
        } /* block 12, paths 1 */
        /* block 13, paths block11+block12 = 2 */
    
        /* outer block, paths block10*block13 = 26 */
    

Each condition is treated as disjoint. In other words, no conclusions are drawn about a condition that is tested more than once.

The true path count through a function usually obeys the inequality:

cyclomatic complexity <= true path count <= static path count

Static path count is one of the three standard metrics used by QAC for demographic analysis.

[1] Nejmeh, B.A. (1988), NPATH: A Measure of Execution Path Complexity and its Applications, Comm ACM, 31, (2), p. 188-200.

RET - Number of Return Points in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

RET is the count of the reachable return statements in the function, plus one if there exists a reachable implicit return at the } that terminates the function.

The following example shows an implicit return:

Example

        void foo( int x, int y )
        {
    	printf( "x=%d, y=%d\n", x, y );
    	/* Here with implicit return. Hence RET = 1*/
        }
    

Structured Programming requires that every function should have exactly one entry and one exit. This is indicated by a RET value of 1. RET is useful when the programmer wants to concentrate on the functions that do not follow the Structured Programming paradigm. For example, those with switch statements with returns in many or every branch.

ST1 - Number of Statements in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

ST2 - Number of Statements in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

ST3 - Number of Statements in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

STx - Number of Statements in Function Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metrics

These metrics count the number of statements in the function body. There are 3 variants on the metric:

ST1 is the base definition and counts all statements tabulated below.
ST2 is ST1 except block, empty statements and labels are not counted.
ST3 is ST2 except declarations are not counted.

The following chart shows the statements counted by the STST metrics:

Statement KindST1ST2ST3
blockyesignoreignore
simple statement followed by ;yesyesyes
empty statementyesignoreignore
declaration statementyesyesignore
labelyesignoreignore
breakyesyesyes
continueyesyesyes
doyesyesyes
foryesyesyes
gotoyesyesyes
ifyesyesyes
returnyesyesyes
switchyesyesyes
whileyesyesyes

The following example shows statements counted by ST1, which for this function yields a value of 10:

Example

        void stst( void )
        {
    	int i;          /* 1 */
        label_1:            /* 2 */
        label_2:            /* 3 */
    	switch ( 1 )    /* 4 */
    	{               /* 5 */
    	case 0:         /* 6 */
    	case 1:         /* 7 */
    	case 2:         /* 8 */
    	default:        /* 9 */
    	    break;      /* 10 */
    	}
        }
    

This metric indicates the maintainability of the function. Number of statements also correlates with most of the metrics defined by Halstead. The greater the number of statements contained in a function, the greater the number of operands and operators, and hence the greater the effort required to understand the function. Functions with high statement counts should be limited. Restructuring into smaller sub-functions is often appropriate.

SUB - Number of Function Calls Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

The number of function calls within a function. Functions with a large number of function calls are more difficult to understand because their functionality is spread across several components. Note that the calculation of SUB is based on the number of function calls and not the number of distinct functions that are called, see CAL.

A large SUB value may be an indication of poor design; for example, a calling tree that spreads too rapidly.
See Brandl (1990)[1] for a discussion of design complexity and how it is highlighted by the shape of the calling tree.

The following code example has an SUB value of 4.

Example

        extern dothis(int);
        extern dothat(int);
        extern dotheother(int);
    
        void test()
        {
    	int a, b;
    	a = 1;
    	b = 0;
    
    	if (a == 1)
    	{
    	    dothis(a);                  /* 1 */
    	} else
    	{
    	    dothat(a);                  /* 2 */
    	}
    	if (b == 1)
    	{
    	    dothis(b);                  /* 3 */
    	} else
    	{
    	    dotheother(b);              /* 4 */
    	}
        }
    

[1] Brandl, D.L. (1990), Quality Measures in Design, ACM Sigsoft Software Engineering Notes, vol 15, 1.

[x] Halstead, Maurice H. (1977). Elements of Software Science.

UNR - Number of Unreachable Statements Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is the count of all statements within the function body that are guaranteed never to be executed. UNR uses the same method for identifying statements as metric ST1. Hence UNR counts the following as statements if unreachable.

Statement Kind Counted
block
simple statement followed by ;
empty statement
declaration statement
label
break
continue
do
for
goto
if
return
switch
while

Example yielding UNR = 4

Example

    void stunr( unsigned i )
    {
        if ( i >= 0 )
        {
    	if ( i >= 0 )
    	{
    	    while ( i >= 0 )
    		return;
    	} else
    	/* unreachable */
    	{
    	    while ( i >= 0 )
    		return;
    	}
        }
        return; /* unreachable */
    }
    

UNV - Unused or Non-Reused Variables Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

An unused variable is one that has been defined but which is never referenced. A non-reused variable is a variable that has a value by assignment but which is never used subsequently.

Such variables are generally clutter and are often evidence of 'software ageing', which is the effect of a number of programmers making changes. The code below has an UNV value of 2.

Example

        int other_result;
        extern int result;
    
        int test()
        {
    	int y;                      /* Unused */
    	int z;
    
    	z = 1;                      /* Non-Reused */
    
    	return (result + other_result);
        }
    

XLN - Number of Executable Lines Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is a count of lines in a function body that have code tokens. Comments, braces, and all tokens of declarations are not treated as code tokens. The function below has an XLN value of 9.

Example

        void fn( int n )
        {
    	int x;
    	int y;
    
    	if ( x )                        /* 1 */
    	{
    	    x++;                        /* 2 */
    	    for (;;)                    /* 3 */
    		/* Ignore comments */
    		/* Ignore braces */
    	    {
    		switch ( n )            /* 4 */
    		{
    		    case 1 : break;     /* 5 */
    		    case 2 :            /* 6 */
    		    case 3 :            /* 7 */
    			break           /* 8 */
    				;       /* 9 */
    		}
    	    }
    	}
        }
    

This metric is used in the computation of the KDN and PDN metrics.

File-Based Metrics Bottom Doc. Button Top Document Button Down Section Button Up Section Button

BMO - Organic Programmer Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

BMS - Semi-detached Programmer Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

BME - Embedded Programmer Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metrics

The COCOMO metrics are produced for each source code file. You can display an estimate of development costs for a whole project by choosing the COCOMO Cost Model option from the Reports menu. See Chapter 6: Reports for a discussion of the COCOMO cost model and an explanation of the three programming modes: Organic, Semi-detached, and Embedded.

These metrics estimate the number of programmer-months required to create the source code in the respective environments.

BME = 3.6 * ( TPP / 1000 ) 1.20
BMO = 2.4 * ( TPP / 1000 ) 1.05
BMS = 3.0 * ( TPP / 1000 ) 1.12

BUG - Residual Bugs (token-based estimate) Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

BUG = 0.001 * EFF2/3

This is an estimate of the number of bugs in the file, based on the number of estimated tokens. Its value would normally be lower than the sum of the function-based PBG values. For a more detailed discussion of software bug estimates, see Hatton and Hopkins,[1].

[1] Hatton, L., Hopkins, T.R., (1989) Experiences With Flint, a Software Metrication Tool for Fortran 77, Symposium on Software Tools, Napier Polytechnic, Edinburgh, Scotland.

CDN - Comment to Code Ratio Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is defined to be the number of visible characters in comments, divided by the number of visible characters outside comments. Comment delimiters are ignored. Whitespace characters in strings are treated as visible characters.

A large value of CDN indicates that there may be too many comments, which can make a module difficult to read. A small value indicates that there may not be enough comments, which can make a module difficult to understand.

The code below has 28 visible characters in comments and 33 visible characters in the code. The resulting CDN value is 0.85.

Example

        int test()
        /* This is a test */
        {
    	int x;
    	int y;
        /* This is another test */
    	return (x + y);
        }
    

The value of CDN is affected by how QAC counts the comments. QAC can count comments in three possible ways:

  • all comments, (a),
  • all comments except for those from headers, (n),
  • inline or internal comments (i). These are comments within functions and comments that annotate a line of code (comments that are on the same line as code at file scope).

DEV - Estimated Development (programmer-days) Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is an estimate of the number of programmer days required to develop the source file. Unlike COCOMO statistics, which are based solely on the number of lines of code, this estimate is derived from the file's difficulty factor. It is a more accurate measure of the development time, especially after the scaling factor has been adjusted for a particular software environment.

DEV = EFF / dev_scaling

where dev_scaling is a scaling factor defined in qac.cfg. The default is 6000.

DIF - Program Difficulty Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is a measure of the difficulty of a translation unit. An average C program has a difficulty of around 12. Anything significantly above this has a rich vocabulary and is potentially difficult to understand.

DIF = VOL / ( (2 + VAR) * log2 (2 + VAR) )

ECT - Number of External Variables Declared Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is a measure of the number of data objects (not including functions) declared with external linkage. It is an indication of the amount of global data being passed between modules. It is always desirable to reduce dependence on global data to a minimum.

Example

        extern int result;
        int other_result;
    
        main()
        {
    	result = 20 + 30;
    	other_result = result * 2;
        }
    

The above code sample has an ECT value of 2.

EFF - Programmer Effort Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a measure of the programmer effort involved in the production of a translation unit. It is used to produce a development time estimate.

EFF = VOL * DIF

FNC - Number of Functions in File Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a count of the number of function definitions in the file.

FCO - Estimated Function Coupling Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

See Brandl[1]. Since the actual value of Brandl's metric requires a full, well-structured calling tree, FCO can only be an estimate. A high figure indicates a large change of complexity between levels of the calling tree. The metric is computed from FNC and the SUB values of the component functions in the translation unit:

FCO = ∑(SUB) - FNC + 1

The code example below has an FCO value of 1 (2 - 2 + 1).

Example

        BOOL isActive(CHANNEL c);
    
        BOOL okToRead(TEXTCHANNEL c)
        {
    	return !isActive(c);
        }
    
        BOOL okToPrint(PRINTCHANNEL c)
        {
    	return !isActive(c);
        }
    

[1] Brandl, D.L. (1990), Quality Measures in Design, ACM Sigsoft Software Engineering Notes, vol 15, 1.

HAL - Halstead Prediction of TOT Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric and also ZIP are predictions derived from the vocabulary analysis metrics OPN and OPT of what the value of TOT should be. If they differ from TOT by more than a factor of 2, it is an indication of an unusual vocabulary. This usually means that either the source code contains sections of rather repetitive code or it has an unusually rich vocabulary. The two metrics are computed as follows:

ZIP = ( OPN + OPT ) * ( 0.5772 + ln (OPN + OPT) )
HAL = OPT * log2 ( OPT ) + OPN * log2 ( OPN )

M20 - Number of Operand Occurrences Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is the number of operands in a software component and is one of the Halstead vocabulary analysis metrics. Halstead considered that a component is a series of tokens that can be defined as either operators or operands.

Unlike OPN, this metric is the count of every instance of an operand in a file, regardless of whether or not it is distinct. OPN only counts the operands that are distinct. The code example below has a M20 value of 8.

Example

        void f( int a )             /* 1,2 -> f, a  */
        {
    	if ( a > 1 )            /* 3,4 -> a, 1  */
    	{
    	    ++a;                /* 5 -> a       */
    	    while ( a > 1 )     /* 6,7 -> a, 1  */
    	    {
    		--a;            /* 8 -> a       */
    	    }
    	}
        }
    

[x] Halstead, Maurice H. (1977). Elements of Software Science.

M21 - Number of Operator Occurrences Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is the number of operators in a software component and is one of the Halstead vocabulary analysis metrics. Halstead considered that a component is a series of tokens that can be defined as either operators or

operands.

Unlike OPT, this metric is the count of every instance of an operator in a file, regardless of whether or not it is distinct. OPT only counts the operators that are distinct. The code example below has a M21 value of 22.

Example

        void f( int a )             /* 1,2,3,4 -> void, (, int, )       */
        {                           /* 5 -> {                           */
    	if ( a > 1)             /* 6,7,8,9 -> if, (, >, )           */
    	{                       /* 10 ->{                           */
    	    ++a;                /* 11,12 -> ++, ;                   */
    	    while (a > 1)       /* 13,14,15,16 -> while, (, >, )    */
    	    {                   /* 17 -> {                          */
    		--a;            /* 18,19 -> --, ;                   */
    	    }                   /* 20 -> }                          */
    	}                       /* 21 -> }                          */
        }                           /* 22 -> }                          */
    

[x] Halstead, Maurice H. (1977). Elements of Software Science.

M22 - Number of Statements Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is the number of statements in a software component. This is a count of semicolons in a file except for the following instances:

  • within for expressions,
  • within struct or union declarations/definitions,
  • within comments,
  • within literals,
  • within preprocessor directives,
  • within old-style C function parameter lists.

The code example below has a M22 value of 5.

Example

        void f( int a )
        {
    	struct { int i;
    		 int j; }
    	    ij;                 /* 1    */
    	a = 1;                  /* 2    */
    	a = 1; a = 2;           /* 3,4  */
    	if
    	    ( a >
    		    1 )
    	{
    	    return;             /* 5    */
    	}
        }
    

M28 - Number of Non-Header Comments Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a count of the occurrences of C or C++ style comments in a source file except for those that are within the header of a file. A file header is defined as tokens preceding the first code token or preprocessor directive token.

M28 is based on the method used to compute CDN but differs from CDN in that CDN counts the visible characters within comments, whereas M28 counts the occurrences of comments. The code example below has a M28 value of 2.

Example

        /* Header comment 1             Count = 0 */
        /* Header comment 2             Count = 0 */
    
        /* Last header comment          Count = 0
           code follows */
    
        #define CENT 100
    
        /* Non header comment           Count = 1 */
        void f( int a )
        {
    	/* Block scope comment      Count = 2 */
    	a = CENT;
    	return;
        }
    

M33 - Number of Internal Comments Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is a count of C style or C++ comments in a source file that are within functions or annotate a line of code at file scope. Comments within functions are all comments at block scope. Comments that annotate code are ones that start or end on the same line as code.

M33 is based on the method used to compute CDN but differs from CDN in that CDN counts the visible characters within comments, whereas M33 counts the occurrences of comments. The code example below has a M33 value of 5.

Example

        /* Header comment 1         Count = 0 */
        /* Header comment 2         Count = 0 */
    
        /* Last header comment      Count = 0
           code follows */
    
        #define CENT 100    /* Annotating comment   M33 = 1 */
    
        int                 /* Annotating comment   M33 = 2 */
    	i;
        /* Annotating comment M33 = 3 */ int j; /*
           Annotating comment M33 = 4 */
        /* Non internal comment                     M33 = 0 */
        void f( int a )
        {
    	/* Block scope comment                  M33 = 5 */
    	a = CENT;
    	return;
        }
    

OPN - Number of Distinct Operands Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This is the number of distinct operands used in the file. Distinct operands are defined as unique identifiers and each occurrence of a literal.

Most literals, except 0 and 1, are usually distinct within a program. Since macros are usually used for fixed success and failure values (such as TRUE and FALSE), the differences in counting strategies are fairly minimal. The code below has an OPN value of 11.

Example

        extern int result;              /* 1 -> result */
        static int other_result;        /* 2 -> other_result */
    
        main()                          /* 3 -> main */
        {
    	int x;                      /* 4 -> x */
    	int y;                      /* 5 -> y */
    	int z;                      /* 6 -> z */
    
    	x = 45;                     /* 7 -> 45 */
    	y = 45;                     /* 8 -> 45 */
    	z = 1;                      /* 9 -> 1 */
    	result = 1;                 /* 10 -> 1 */
    	other_result = 0;           /* 11 -> 0 */
    
    	return (x + other_result);
        }
    

OPT - Number of Distinct Operators Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This covers any source code tokens not supplied by the user, such as keywords, operators, and punctuation. OPT is used in the calculation of a number of other metrics.

The code below has an OPT value of 11.

Example

        extern int result;              /* 1,2,3 -> extern, int, ; */
        static int other_result;        /* 4 -> static */
    
        main()                          /* 5,6 -> ()*/
        {                               /* 7 -> { */
    	int x;
    	int y;
    	int z;
    
    	x = 45;                     /* 8 -> = */
    	y = 45;
    	z = 1;
    	result = 1;
    	other_result = 0;
    
    	return (x + other_result);  /* 9,10 -> return, + */
        }                               /* 11 -> } */
    

SCT - Number of Static Variables Declared Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Function-Based Metric

This metric is computed as the number of variables and functions declared static at file scope. The code example below has an SCT value of 2.

Example

        static int other_result;                /* 1 */
        int result;
    
        static int test()                       /* 2 */
        {
    	int x;
    	int y;
    	int z;
    
    	z = 1;
    
    	return (x + other_result);
        }
    

SHN - Shannon Information Content Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

Also known as the "entropy" H, this metric is a widely recognized algorithm for estimating the program space required to encode the functions in a source file. SHN is measured in bits and is calculated as follows:

SHN = ZIP * log2 (√(OPN + OPT) + ln (OPN + OPT))

TDE - Embedded Total Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

TDO - Organic Total Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

TDS - Semi-detached Total Months Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metrics

The COCOMO metrics are produced for each source code file. You can display an accurate estimate of development costs for a whole project by choosing the COCOMO Cost Model option from the Reports menu. Refer to Chapter 6: Reports for a discussion of the COCOMO cost model and an explanation of the three programming modes: Organic, Semi-detached, and Embedded.

These metrics are a measure of elapsed time in months required to develop the source code in the respective environments.

TDE = 2.5 * BME 0.32
TDO = 2.5 * BMO 0.38
TDS = 2.5 * BMS 0.35

TLN - Total Preprocessed Code Lines Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This metric is a count of the total number of source lines in the file after pre-processing. The pre-processed file will reflect the processing of include files, pre-processor directives and the stripping of comment lines.
Empty lines are not counted.

See also TPP

TOT - Total Number of Tokens Used Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This metric is the total number of tokens, not distinct tokens, in the source file. The code example below has an TOT value of 19.

Example

        int test()                  /* 1,2,3,4 */
        {                           /* 5 */
    	int x;                  /* 6,7,8
    	int y;                  /* 9,10,11 */
    	/*Excluded Comment*/
    	return (x + y);         /* 12,13,14,15,16,17,18 */
        }                           /* 19 */
    

TPP - Total Unpreprocessed Code Lines Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This metric is a count of the total number of source lines in the file before pre-processing.

See also TLN

VAR - Total Number of Variables Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

The metric represents the total number of distinct identifiers. The code below has an VAR value of 5.

Example

        int other_result;           /* 1 */
        extern int result;          /* 2 */
    
        int test()                  /* 3 */
        {
    	int x;                  /* 4 */
    	int y;                  /* 5 */
    
    	return (x + y + other_result);
        }
    

VOL - Program Volume Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This is a measure of the number of bits required for a uniform binary encoding of the program text. It is used to calculate various Halstead vocabulary metrics.

The following is the calculation for the program volume:

VOL = TOT * log 2 ( OPN + OPT )

[x] Halstead, Maurice H. (1977). Elements of Software Science.

ZIP - Zipf Prediction of TOT Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

ZIP = ( OPN + OPT ) * ( 0.5772 + ln (OPN + OPT) )

See HAL.

CCA - Total Number of Characters Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This metric is the total number of characters in the file. Only visible characters are counted, except in string or character literals, in which case all characters are counted and tabs are treated as one character. When counting comment characters, the comment delimiter characters are counted.

CCB - Total Number of Code Characters Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

File-Based Metric

This metric is the total number of code characters in the file. Only visible characters are counted, except in string or character literals, in which case all characters are counted and tabs are treated as one character. Characters comprising comments are not counted, this includes the comment delimiter characters.

CCC - Total Number of Comment Characters Bottom Doc. Button Top Document Button Down Section Button Up Section Button Blank Up Chapter Button

File-Based Metric

This metric is the total number of visible comment characters in the file. The comment delimiter characters are not counted.

Class-Based Metrics Bottom Doc. Button Top Document Button Down Section Button Up Section Button

CBO - Coupling between objects Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

Class-Based Metric

This is a count of the number of methods (member functions) or member objects of other classes accessed by a class. Only classes outside the inheritance hierarchy are considered because you would expect interaction with base and derived classes. Coupling to classes outside the inheritance tree should be viewed with suspicion as it makes the class less independent and less re-usable. This is one of Chidamber & Kemerer's[1] suite of object oriented metrics.

[1] Chidamber, S.R. and Kemerer, C.F. (1991). Towards a Metrics Suite for Object Oriented Design, Proceedings of OOPSLA, '91, Sigplan notices, vol.26, no. 11, ACM Press.

DIT - Deepest level of inheritance Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

This represents the number of derivations from the furthest base class down to this class. A high figure may indicate that the class depends on accumulated functionality, which makes understanding the class potentially difficult. This is one of the metrics defined by Chidamber & Kemerer.

LCM - Lack of cohesion of methods within a class Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

Methods within a class are partitioned into sets that access independent sets of member objects. The LCM metric is a count of sets of unrelated members for a type.

For example (default):

Example

        class cohesive
        {
        private:
    	int i1;
    	int i2;
    	int i3;
        public:
    	void m1(int a) { i1 = a + i2; }
    	void m2(int a) { i2 = a; }
    	void m3(int a) { if (a > i3) ++i3; }
        };
    

This above code sample has a LCM value of 2 because methods m1 and m2 access the set of member objects i1 and i2. Method m3 accesses only i3 and can be viewed as independent of m1 and m2. (m3 is not cohesive with the other two methods).

Similarly, where one method calls another, the set used for inclusion in LCM is the union of the sets from each method.

Variations of the calculation of LCM may explicitly exclude constructors, so the default behavior of CMA is that constructors are excluded when calculating this metric. To include constructors, enable the configuration option "-ProdOption LCM::include_constructor".

If constructors are included, and the constructor for such a type initializes all the members, then the value of LCM is guaranteed to be '1'.

This is one of the metrics defined by Chidamber & Kemerer.

MTH - Number of methods declared in class Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

The number of methods declared within a class. This does not include methods declared in base classes. Classes with a large number of methods will be difficult to understand.

NOC - Number of immediate children Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

This is the number of classes for which this class is an immediate base class. A high figure for this metric indicates greater dependence on the functionality of this class, and more potential knock-on effects from changes to it. This is one of the metrics defined by Chidamber & Kemerer.

NOP - Number of immediate parents Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

This metric indicates the number of inheritances for a class. Root base classes have a value of 0 while classes derived with a single inheritance have a value of 1. Classes that have multiple inheritance are prohibited by some programming standards.

RFC - Response for class Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Class-Based Metric

This indicates how functions can potentially be called directly from the class. The response set is calculated as the number of distinct class methods and functions called from the definitions of those methods. This is one of the metrics defined by Chidamber & Kemerer.

WMC - Weighted methods per class Bottom Doc. Button Top Document Button Down Section Button Up Section Button Blank Up Chapter Button

Class-Based Metric

This is the sum of cyclomatic complexities (See Cyclomatic complexity (CYC) in Function-Based Metrics section of this document) for all the methods in the class. In the same way that cyclomatic complexity gives an indication of the amount of testing required for an individual function, this metric gives an indication of the amount of testing required for a whole class. This is one of the metrics defined by Chidamber & Kemerer.

Project-Wide Metrics Bottom Doc. Button Top Document Button Down Section Button Up Section Button

NRA - Number of Recursions Across Project Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

Project-Wide Metric

This metric is defined to be the number of recursive paths in the call graph of the project's functions. A recursive path can be for one or more functions. The minimum, and often desirable, value of this metric is zero. Values greater than zero indicate the number of distinct loops in the call graph.

NEA - Number of Entry points Across Project Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Project-Wide Metric

This metric is the number of functions that are not called in the project. It is the number of nodes in the call graph which are not themselves called. For example, main() is not called; hence the minimum (build) value of 1.

NFA - Number of Functions Across Project Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

Project-Wide Metric

This metric is the number of function definitions in the project. Note that this metric is the sum of QAC's FNC metric values for each source file included in the project.

CYA - Cyclomatic Complexity Across Project Bottom Doc. Button Top Document Button Down Section Button Up Section Button Blank Up Chapter Button

Project-Wide Metric

This metric is the sum of cyclomatic complexity values for each function definition in the project. Note that this metric is the sum of QAC CYC metric values for each source file included in the project.

General Bottom Doc. Button Top Document Button Down Section Button Up Section Button

The Components of Function Structure Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Blank

Function structure diagrams show the control flow structures within source code. Decisions (if, switch, and the condition part of a loop) are displayed as forks in the structure. The corresponding join, further to the right, indicates where the paths rejoin. Backward arcs, caused by loops, are shown as dotted lines.

The function structure diagrams show the following code structures:

  • straight code
  • if
  • if else
  • switch
  • while loop
  • for loop
  • nested structures
  • break in a loop
  • return in a loop
  • continue in a loop
  • unreachable code

Each component progresses from the left to the right as the control flow would progress through the source code.

Straight code Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
    static int code = 0;
    
        void funcStraight( void)
        {
    	code = 1;
        }
    

There is only one path through this particular function, which is represented as lying along the x-axis.

If Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
    
        void funcIf( void)
        {
    	if (code > 0)
    	{
    	    code = 1;
    	}
        }
    

This function has two paths. The first path is through the if statement and is shown by the raised line. The second path is where the if condition is false and is represented by the x-axis.

If-Else Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
    
        void funcIfElse( void)
        {
    	if (code > 0)
    	{
    	    code = 3;
    	} else
    	{
    	    code = 4;
    	}
        }
    

This function has two execution paths. The first path is the if sub-statement represented by the raised line. The second path is the else sub-statement represented by the x-axis.

Note that the body of this structure is longer than the body of the if statement. If the two arms of the if-else were not straight line code, the body of the if branch would appear at the left hand end of the raised line and the body of the else branch would appear to the right of the lower line.

Switch Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

        static int code = 0;
    
        void funcSwitch( void)
        {
    	switch (code)
    	{
    	case 1:
    	    if (code == 1)
    	    {
    		/* block of code */
    	    }
    	    break;
    	case 2:
    	    break;
    	case 3:
    	    if (code == 3)
    	    {
    		/* block of code */
    	    }
    	    break;
    	default:
    	    break;
    	}
        }
    

In the switch statement, the x-axis represents the default action, and each case statement is shown by a raised line. The two briefly raised lines represent the if statements within case 1 and case 3.

The diagram shows how the if statements are staggered. The if of case 1 is shown on the left and the if of case 3 is shown on the right.

While loop Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
    
        void funcWhile( void)
        {
    	while (code > 0)
    	{
    	    --code;
    	}
        }
    

In the while loop, the x-axis represents the path straight through the function as though the while loop had not been executed. The solid raised line shows the path of the while body. The dotted line shows the loop to the beginning of the while statement.

For loop Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
        void doSomethingWith(int);
    
        void funcFor( void)
        {
    	int i;
    	for (i = 0; i > code; ++i)
    	{
    	    doSomethingWith( i);
    	}
        }
    

The for loop is similar to the while loop as for loops can be rewritten as while loops. For example, funcFor in the above example could be written as:

    
        void funcFor( void)
        {
    	int i = 0;
    	while (i > code)
    	{
    	    /* body */
    	    ++i;
    	}
        }
    

Nested Structures Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
    
        void funcWhileIfElse( void)
        {
    	while (code > 0)
    	{
    	    if (code == 1)
    	    {
    		code = 0;
    	    } else
    	    {
    		code--;
    	    }
    	}
        }
    

This is an if-else contained within a while loop. The first solid raised line represents the while loop while the inner raised solid line represents the if-else loop. Other function structure components can be similarly nested.

Break in a loop Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
    
        void funcWhileIfBreak( void)
        {
    	while (code > 0)
    	{
    	    if (code == 3)
    	    {
    		break;
    	    }
    	    code--;
    	}
    	if (code == 0)
    	{
    	    code++;
    	}
        }
    

The break jumps to the end of the while statement and causes a knot. A knot is where the control flow crosses the boundary of another statement block and indicates unstructured code. In this case, break jumps to the end of the while statement and the next part of the program, the if statement, is executed.

Return in a loop Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
    
        void funcWhileIfReturn( void)
        {
    	while (code > 0)
    	{
    	    if (code == 3)
    	    {
    		return;
    	    }
    	    code--;
    	}
    	if (code == 0)
    	{
    	    code++;
    	}
        }
    

The return statement causes the program to jump to the end of the function. This jump breaks the control flow and causes a knot in the code.

Continue in a loop Bottom Doc. Button Top Document Button Down Section Button Up Section Button Down Chapter Button Up Chapter Button

    
        static int code = 0;
        void funcWhileIfContinue( void)
        {
    	while (code > 0)
    	{
    	    if (code == 3)
    	    {
    		continue;
    	    }
    	    code--;
    	}
    	if (code == 0)
    	{
    	    code++;
    	}
        }
    

The continue statement causes the program to jump back to the beginning of the while loop.

Unreachable code Bottom Doc. Button Top Document Button Blank Up Section Button Blank Up Chapter Button

    
        static void funcUnReach( int i)
        {
    	if (i)
    	{
    	    i = 1;
    	}
    
    	goto Bad;
    
    	if (i)
    	{
    	    i = 2;
    	}
    
        Bad:
    	if (i)
    	{
    	    i = 3;
    	}
    
    	return;
        }
    

The raised red section represents code that is unreachable.

The structure and approximate position of the unreachable code is shown. It occurs after the first if condition and before the last if condition. Its position above the main structure shows that the control flow misses the middle if condition.


metrics.html