CertC-DCL19¶
Minimize the scope of variables and functions
Required inputs: IR
Variables and functions should be declared in the minimum scope from which all references to the identifier are still possible.
When a larger scope than necessary is used, code becomes less readable, harder to maintain, and more likely to reference unintended variables (see DCL01-C. Do not reuse variable names in subscopes).
Noncompliant Code Example
In this noncompliant code example, the function
counter() increments the global variable
count and then returns immediately if this variable exceeds a
maximum value:
unsigned int count = 0;
void counter() {
if (count++ > MAX_COUNT) return;
/* ... */
}
Assuming that the variable
count is only accessed from this function, this example is
noncompliant because it does not define
count within the minimum possible scope.
Compliant Solution
In this compliant solution, the variable
count is declared within the scope of the
counter() function as a static variable. The static modifier, when
applied to a local variable (one inside of a function), modifies the lifetime
(duration) of the variable so that it persists for as long as the program does
and does not disappear between invocations of the function.
void counter() {
static unsigned int count = 0;
if (count++ > MAX_COUNT) return;
/* ... */
}
The keyword
static also prevents reinitialization of the variable.
Noncompliant Code Example
The counter variable
i is declared outside of the
for loop, which goes against this recommendation because it is not
declared in the block in which it is used. If this code were reused with
another index variable
j, but there was a previously declared variable
i, the loop could iterate over the wrong variable.
size_t i = 0;
for (i=0; i < 10; i++){
/* Perform operations */
}
Compliant Solution
Complying with this recommendation requires that you declare variables where
they are used, which improves readability and reusability. In this
example, you would declare the loop's index variable
i within the initialization of the
for loop. This requirement was recently relaxed in the C Standard.
for (size_t i=0; i < 10; i++) {
/* Perform operations */
}
Noncompliant Code Example (Function Declaration)
In this noncompliant code example, the function
f() is called only from within the function
g(), which is defined in the same compilation unit. By default,
function declarations are extern, meaning that these functions are
placed in the global symbol table and are available from other compilation
units.
int f(int i) {
/* Function definition */
}
int g(int i) {
int j = f(i);
/* ... */
}
Compliant Solution
In this compliant solution, the function
f() is declared with internal linkage. This practice limits the
scope of the function declaration to the current compilation unit
and prevents the function from being included in the external symbol
table. It also limits cluttering in the global name space and prevents the
function from being accidentally or intentionally invoked from another
compilation unit. See
DCL15-C.
Declare file-scope objects or functions that do not need external linkage as
static for more information.
static int f(int i) {
/* Function definition */
}
int g(int i) {
int j = f(i);
/* ... */
}
Risk Assessment
Failure to minimize scope could result in less reliable, readable, and reusable code.
| Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| DCL19-C | Low | Unlikely | Medium | P2 | L3 |
Related Guidelines
| SEI CERT C++ Coding Standard | VOID DCL07-CPP. Minimize the scope of variables and methods |
| MISRA C:2012 | Rule 8.9 (advisory) |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
function_file_static |
{} can be declared static in primary file. |
None |
False |
locality_block |
{} can be declared in a more local scope. |
None |
False |
locality_function |
Global {} can be declared inside function. |
None |
False |
locality_function_static |
Global {} can be declared as local static inside function. |
None |
False |
locality_loop_init |
{} can be declared in the for-loop’s initialization. |
None |
False |
var_file_static |
{} can be declared static in primary file. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
allow_moving_to_other_primary_file¶
allow_moving_to_other_primary_file : bool = False
check_loop_counter¶
check_loop_counter : bool = True
consider_constructors_as_capturing¶
consider_constructors_as_capturing : bool = False
exclude_c_function_locals¶
exclude_c_function_locals : bool = False
exclude_dllexport¶
exclude_dllexport : bool = True
exclude_function_locals¶
exclude_function_locals : bool = True
exclude_undefined¶
exclude_undefined : bool = True
move_global_const_into_function¶
move_global_const_into_function : bool = True
only_check_unit_locals¶
only_check_unit_locals : bool = False
template_args_can_be_static¶
template_args_can_be_static : bool = False