Portability checks
Some nonportable code is flagged by lint
in its default behavior, and a few more cases are diagnosed when lint
is invoked with -p and/or -Xc.
The latter tells lint to check
for constructs that do not conform to the ANSI C standard.
For the messages issued under -p and -Xc,
check
``Using lint''.
Examples:
-
In some C language implementations,
character variables that are not explicitly
declared signed or unsigned
are treated as signed quantities with a
range typically from -128 to 127.
In other implementations, they are treated as
nonnegative quantities
with a range typically from 0 to 255.
So the test
char c;
c = getchar();
if (c == EOF) . . .
where EOF has the value -1,
will always fail on machines where character
variables take on nonnegative values.
One of lint's -p checks
will flag any comparison that implies
a ``plain'' char may have a negative
value.
Note, however, that declaring c a signed char
in the above example eliminates the diagnostic,
not the problem.
That's because getchar() must return all
possible characters and a distinct EOF value,
so a char cannot store its value.
This example, which is perhaps the most
common one arising from implementation-defined
sign-extension, shows how a thoughtful
application of lint's portability
option can help you discover bugs not related to portability.
In any case, declare c as an int.
-
A similar issue arises with bit-fields.
When constant values are
assigned to bit-fields, the field may be too
small to hold the value.
On a machine that treats bit-fields of type int
as unsigned quantities, the values allowed for
int x:3 range from 0 to 7, whereas on machines
that treat them as signed quantities
they range from -4 to 3.
However unintuitive it may seem, a three-bit field
declared type int cannot hold the value 4
on the latter machines.
lint invoked with -p
flags all bit-field types other
than unsigned int or signed int.
Note that these are the only portable
bit-field types.
The compilation system supports int, char,
short, and long bit-field types
that may be unsigned, signed, or ``plain.''
It also supports the enum bit-field type.
-
Bugs can arise when a larger-sized
type is assigned to a smaller-sized type.
If significant bits are truncated, accuracy is lost:
short s;
long l;
s = l;
lint flags all such assignments by default;
the diagnostic can be suppressed by invoking the -a option.
Bear in mind that you may be suppressing
other diagnostics when you invoke lint with this or
any other option.
Check the list in
``Using lint''
for the options that suppress more than one diagnostic.
-
A cast of a pointer to one object type to a
pointer to an object type with stricter alignment
requirements may not be portable.
lint flags
int fun(y)
char y;
{
return(int )y;
}
because, on most machines, an int cannot start on an
arbitrary byte boundary, whereas a char can.
If you suppress the diagnostic by invoking lint
with -h, you may be disabling other messages.
You can eliminate the problem
by using the generic pointer void .
-
ANSI C leaves the order of evaluation of complicated
expressions undefined.
What this means is that when function calls, nested assignment
statements, or the increment and decrement operators
cause side effects -- when
a variable is changed as a byproduct of the
evaluation of an expression -- the order
in which the side effects take place is highly machine dependent.
By default, lint flags any variable
changed by a side effect and used elsewhere
in the same expression:
int a[10];
main()
{
int i = 1;
a[i++] = i;
}
Note that in this example the value of a[1] may
be 1 if one compiler is used, 2 if another.
The bitwise logical operator & can also give
rise to this diagnostic when it is mistakenly
used in place of the logical operator &&:
if ((c = getchar()) != EOF & c != '0')
Next topic:
Suspicious constructs
Previous topic:
Consistency checks
© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003