|
Possibly Uninitialized
This discussion deals with messages 644, 645 ("may not
have been initialized"), 771, 772 ("conceivably not
initialized"), 530 ("not initialized"), and
1401 - 1403 ("member ... not initialized"). These messages
refer to auto variables and data members while in constructors.
For example, given the code
if( a ) b = 6;
else c = b;
a = c;
assume that neither b nor c were previously initialized.
PC-lint/FlexeLint reports that b is not initialized (when its
value is assigned to c) and that c may not have been
initialized (when its value is assigned to a).
In earlier versions (and in conventional lint's) a single unintelligent
sweep is taken which would regard b and c as having been
initialized prior to use.
while loops and for loops are not quite the same
as if statements. Consider, for example, the following code:
while ( n-- )
{
b = 6;
.
.
.
}
c = b;
assuming that b had not been initialized earlier, we report
that b is "conceivably not initialized" when
assigned to c and give a lighter Informational message. The reason
for distinguishing this case from the earlier one is that it could be that
the programmer knows the body of the loop is always taken at least once.
By contrast, in the earlier case involving if statements, the
programmer would be hard-pressed to say that the if condition
is always taken, for that would imply, at the least, some redundant code
which could be eliminated.
The switch is more like an if than a while.
For example,
switch ( k )
{
case 1: b = 2; break;
case 2: b = 3;
/* Fall Through */
case 3: a = 4; break;
default: error();
}
c = b;
Although b has been assigned a value in two different places,
there are paths that might result in b not being initialized.
Thus, when b is assigned to c a possibly-uninitialized
message is obtained. To fix things up you could assign a default value
to b before the switch. This quiets lint but then you
lose the initialization detection in the event of subsequent modifications.
A better approach may be to fix up the case's for which b
has not been assigned a value. We will show this below.
If the invocation of error() is one of those instances which
"can't occur but I'll report it anyway," then you should let
PC-lint/FlexeLint know that this section of code is not reachable. If
error() does not return, it should be marked as not returning by using
the option
-function(exit,error)
This transfers the special property of the exit function
to error. Alternatively, you may mark the return point as unreachable
as shown in the following fixed up example:
switch ( k )
{
case 1: b = 2; break;
case 2:
case 3: b = 3; a = 4; break;
default: error();
/*lint -unreachable */
}
c = b;
Don't make the mistake of placing the -unreachable directive
before the call to error() as this property is not transmitted
across the call. If there is a break after the call, make sure
the directive is placed before the break. Code after a
break, is never considered reachable, so the directive placed after
the break would have no effect.
Another way to get the "not initialized" message
is to pass a pointer variable to free (or to some function like
free -- see Function Mimicry. For example:
if( n ) free( p );
.
.
.
p->value = 3;
will result in p being considered as possibly not initialized
at the point of access.
Forward goto's are supported in the sense that the initialization
state of the goto is merged with that of the label. Thus, if
b is not yet initialized, the code:
if ( a ) goto label;
b = 0;
label: c = b;
will receive a possibly-uninitialized message when b is
assigned to c. However, backward goto's, since they do
not reduce the initialization state, are ignored.
When the checking for possibly uninitialized variables is first applied
to a large mature project, there will be a small number of false hits.
Experience indicates that they usually involve code that is not especially
well structured or may involve some variation of the following construct:
if( x ) initialize y
.
.
.
if( x ) use y
For these cases simply add an initializer to the declaration for
y or use the option -esym(644,y).
Data members are considered to be initially uninitialized in constructors.
For example:
class X
{
// Warnings 1401 and 1402
X() { if(n) n = 3; }
int n;
int m;
};
results in the message 1402 that n is not initialized when
it is accessed and message 1401 that m has not been initialized
by the constructor. Calling a member function (that is not const)
changes things:
class X
{
// the call to f() inhibits initialization warnings
X() { f(); if( n ) n = 3; }
void f();
int n;
int m;
};
If X::f() was const or if some non member function
were called instead, no assumptions about initialization would be made:
class X
{
// Warnings 1401 and 1402 are issued
X() { g(); if( n ) n = 3; }
void g() const;
int n;
int m;
};
|
|
|
Home | Contact
| Order
PC-lint and FlexeLint are trademarks of Gimpel Software
Copyright © 2011, Gimpel Software, All rights reserved.
|
|