2 |
7u83 |
1 |
<!-- Crown Copyright (c) 1998 -->
|
|
|
2 |
<HTML>
|
|
|
3 |
<HEAD>
|
|
|
4 |
<TITLE>C Checker Reference Manual: Type Checking</TITLE>
|
|
|
5 |
</HEAD>
|
|
|
6 |
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
|
|
|
7 |
<A NAME=S15>
|
|
|
8 |
<H1>C Checker Reference Manual</H1>
|
|
|
9 |
<H3>January 1998</H3>
|
|
|
10 |
<A HREF="tdfc7.html"><IMG SRC="../images/next.gif" ALT="next section"></A>
|
|
|
11 |
<A HREF="tdfc5.html"><IMG SRC="../images/prev.gif" ALT="previous section"></A>
|
|
|
12 |
<A HREF="tdfc1.html"><IMG SRC="../images/top.gif" ALT="current document"></A>
|
|
|
13 |
<A HREF="../index.html"><IMG SRC="../images/home.gif" ALT="TenDRA home page">
|
|
|
14 |
</A>
|
|
|
15 |
<IMG SRC="../images/no_index.gif" ALT="document index"><P>
|
|
|
16 |
<HR>
|
|
|
17 |
<DL>
|
|
|
18 |
<DT><A HREF="#S16"><B>3.1 </B> - Introduction</A><DD>
|
|
|
19 |
<DT><A HREF="#S17"><B>3.2 </B> - Type conversions</A><DD>
|
|
|
20 |
<DL>
|
|
|
21 |
<DT><A HREF="#S18"><B>3.2.1 </B> - Integer to integer conversions
|
|
|
22 |
</A><DD>
|
|
|
23 |
<DT><A HREF="#S19"><B>3.2.2 </B> - Pointer to integer and integer
|
|
|
24 |
to pointer conversions</A><DD>
|
|
|
25 |
<DT><A HREF="#S20"><B>3.2.3 </B> - Pointer to pointer conversions
|
|
|
26 |
</A><DD>
|
|
|
27 |
<DT><A HREF="#S21"><B>3.2.4 </B> - Example: 64-bit portability issues</A><DD>
|
|
|
28 |
</DL>
|
|
|
29 |
<DT><A HREF="#S22"><B>3.3 </B> - Function type checking</A><DD>
|
|
|
30 |
<DL>
|
|
|
31 |
<DT><A HREF="#S23"><B>3.3.1 </B> - Type checking non-prototyped functions</A>
|
|
|
32 |
<DD>
|
|
|
33 |
<DT><A HREF="#S24"><B>3.3.2 </B> - Checking printf strings</A><DD>
|
|
|
34 |
<DT><A HREF="#S25"><B>3.3.3 </B> - Function return checking</A><DD>
|
|
|
35 |
</DL>
|
|
|
36 |
<DT><A HREF="#S26"><B>3.4 </B> - Overriding type checking</A><DD>
|
|
|
37 |
<DL>
|
|
|
38 |
<DT><A HREF="#S27"><B>3.4.1 </B> - Implicit Function Declarations</A><DD>
|
|
|
39 |
<DT><A HREF="#S28"><B>3.4.2 </B> - Function Parameters</A><DD>
|
|
|
40 |
<DT><A HREF="#S29"><B>3.4.3 </B> - Incompatible promoted function
|
|
|
41 |
arguments</A><DD>
|
|
|
42 |
<DT><A HREF="#S30"><B>3.4.4 </B> - Incompatible type qualifiers</A><DD>
|
|
|
43 |
</DL>
|
|
|
44 |
</DL>
|
|
|
45 |
|
|
|
46 |
<HR>
|
|
|
47 |
<H1>3 Type Checking</H1>
|
|
|
48 |
<A NAME=S16>
|
|
|
49 |
<HR><H2>3.1 Introduction</H2>
|
|
|
50 |
Type checking is relevant to two main areas of C. It ensures that
|
|
|
51 |
all declarations referring to the same object are consistent (clearly
|
|
|
52 |
a pre-requisite for a well-defined program). It is also the key to
|
|
|
53 |
determining when an undefined or unexpected value has been produced
|
|
|
54 |
due to the type conversions which arise from certain operations in
|
|
|
55 |
C. Conversions may be explicit (conversion is specified by a cast)
|
|
|
56 |
or implicit. Generally explicit conversions may be regarded more leniently
|
|
|
57 |
since the programmer was obviously aware of the conversion, whereas
|
|
|
58 |
the implications of an implicit conversion may not have been considered.<P>
|
|
|
59 |
<A NAME=S17>
|
|
|
60 |
<HR><H2>3.2 <A NAME=2>Type conversions</H2>
|
|
|
61 |
The only types which may be interconverted legally are integral types,
|
|
|
62 |
floating point types and pointer types. Even if these rules are observed,
|
|
|
63 |
the results of some conversions can be surprising and may vary on
|
|
|
64 |
different machines. The checker can detect three categories of conversion:
|
|
|
65 |
integer to integer conversions, pointer to integer and integer to
|
|
|
66 |
pointer conversions, and pointer to pointer conversions.<P>
|
|
|
67 |
In the default mode, the checker allows all integer to integer conversions,
|
|
|
68 |
explicit integer to pointer and pointer to integer conversions and
|
|
|
69 |
the explicit pointer to pointer conversions defined by the ISO C standard
|
|
|
70 |
(all conversions between pointers to function types and other pointers
|
|
|
71 |
are undefined according to the ISO C standard).<P>
|
|
|
72 |
Checks to detect these conversions are controlled by the pragma:<P>
|
|
|
73 |
<PRE>
|
|
|
74 |
#pragma TenDRA conversion analysis <EM>status</EM>
|
|
|
75 |
</PRE>
|
|
|
76 |
Unless explicitly stated to the contrary, throughout the rest of the
|
|
|
77 |
document where <EM>status</EM> appears in a pragma statement it represents
|
|
|
78 |
one of <CODE>on</CODE> (enable the check and produce errors),
|
|
|
79 |
<CODE>warning</CODE> (enable the check but produce only warnings),
|
|
|
80 |
or <CODE>off</CODE> (disable the check). Here <EM>status</EM> may
|
|
|
81 |
be <CODE>on</CODE> to give an error if a conversion is detected, <CODE>warning
|
|
|
82 |
</CODE> to produce a warning if a conversion is detected, or <CODE>off</CODE>
|
|
|
83 |
to switch the checks off. The checks may also be controlled using
|
|
|
84 |
the command line option<CODE>
|
|
|
85 |
-X:</CODE><EM>test</EM><CODE>=</CODE><EM>state</EM><CODE> </CODE>where
|
|
|
86 |
<EM>test</EM> is one of <CODE>convert_all</CODE>, <CODE>convert_int</CODE>,
|
|
|
87 |
<CODE>convert_int_explicit</CODE>, <CODE>convert_int_implicit</CODE>,
|
|
|
88 |
<CODE>convert_int_ptr</CODE> and <CODE>convert_ptr</CODE> and <EM>state</EM>
|
|
|
89 |
is <CODE>check</CODE>,<CODE>warn</CODE> or <CODE>dont</CODE>.<P>
|
|
|
90 |
Due to the serious nature of implicit pointer to integer, implicit
|
|
|
91 |
pointer to pointer conversions and undefined explicit pointer to pointer
|
|
|
92 |
conversions, such conversions are flagged as errors by default. These
|
|
|
93 |
conversion checks are not controlled by the global conversion analysis
|
|
|
94 |
pragma above, but must be controlled by the relevant individual pragmas
|
|
|
95 |
given in sections <A HREF="#8">3.2.2</A> and <A HREF="#11">3.2.3</A>.<P>
|
|
|
96 |
<A NAME=S18>
|
|
|
97 |
<H3>3.2.1 <A NAME=5>Integer to integer conversions</H3>
|
|
|
98 |
All integer to integer conversions are allowed in C, however some
|
|
|
99 |
can result in a loss of accuracy and so may be usefully detected.
|
|
|
100 |
For example, conversions from int to long never result in a loss of
|
|
|
101 |
accuracy, but conversions from long to int may. The detection of these
|
|
|
102 |
shortening conversions is controlled by:<P>
|
|
|
103 |
<PRE>
|
|
|
104 |
#pragma TenDRA conversion analysis ( int-int ) <EM>status</EM>
|
|
|
105 |
</PRE>
|
|
|
106 |
Checks on explicit conversions and implicit conversions may be controlled
|
|
|
107 |
independently using:<P>
|
|
|
108 |
<PRE>
|
|
|
109 |
#pragma TenDRA conversion analysis ( int-int explicit ) <EM>status</EM>
|
|
|
110 |
</PRE>
|
|
|
111 |
and<P>
|
|
|
112 |
<PRE>
|
|
|
113 |
#pragma TenDRA conversion analysis ( int-int implicit ) <EM>status</EM>
|
|
|
114 |
</PRE>
|
|
|
115 |
Objects of enumerated type are specified by the ISO C standard to
|
|
|
116 |
be compatible with an implementation-defined integer type. However
|
|
|
117 |
assigning a value of a different integral type other then an appropriate
|
|
|
118 |
enumeration constant to an object of enumeration type is not really
|
|
|
119 |
in keeping with the spirit of enumerations. The check to detect the
|
|
|
120 |
implicit integer to enum type conversions which arise from such assignments
|
|
|
121 |
is controlled using:<P>
|
|
|
122 |
<PRE>
|
|
|
123 |
#pragma TenDRA conversion analysis ( int-enum implicit ) <EM>status</EM>
|
|
|
124 |
</PRE>
|
|
|
125 |
Note that only implicit conversions are flagged; if the conversion
|
|
|
126 |
is made explicit, by using a cast, no errors are raised. <P>
|
|
|
127 |
As usual <EM>status</EM> must be replaced by <CODE>on</CODE>, <CODE>warning
|
|
|
128 |
</CODE> or <CODE>off</CODE> in all the pragmas listed above.<P>
|
|
|
129 |
The interaction of the integer conversion checks with the integer
|
|
|
130 |
promotion and arithmetic rules is an extremely complex issue which
|
|
|
131 |
is further discussed in Chapter 4.<P>
|
|
|
132 |
<A NAME=S19>
|
|
|
133 |
<H3>3.2.2 <A NAME=8>Pointer to integer and integer to pointer conversions</H3>
|
|
|
134 |
Integer to pointer and pointer to integer conversions are generally
|
|
|
135 |
unportable and should always be specified by means of an explicit
|
|
|
136 |
cast. The exception is that the integer zero and null pointers are
|
|
|
137 |
deemed to be inter-convertible. As in the integer to integer conversion
|
|
|
138 |
case, explicit and implicit pointer to integer and integer to pointer
|
|
|
139 |
conversions may be controlled separately using:<P>
|
|
|
140 |
<PRE>
|
|
|
141 |
#pragma TenDRA conversion analysis ( int-pointer explicit ) <EM>status</EM>
|
|
|
142 |
</PRE>
|
|
|
143 |
and<P>
|
|
|
144 |
<PRE>
|
|
|
145 |
#pragma TenDRA conversion analysis ( int-pointer implicit ) <EM>status</EM>
|
|
|
146 |
</PRE>
|
|
|
147 |
or both checks may be controlled together by:<P>
|
|
|
148 |
<PRE>
|
|
|
149 |
#pragma TenDRA conversion analysis ( int-pointer ) <EM>status</EM>
|
|
|
150 |
</PRE>
|
|
|
151 |
where <EM>status</EM> may be <CODE>on</CODE>, <CODE>warning</CODE>
|
|
|
152 |
or <CODE>off</CODE> as before and <CODE>pointer-int</CODE> may be
|
|
|
153 |
substituted for <CODE>int-pointer</CODE>.<P>
|
|
|
154 |
<P>
|
|
|
155 |
<A NAME=S20>
|
|
|
156 |
<H3>3.2.3 <A NAME=11>Pointer to pointer conversions.
|
|
|
157 |
</H3>
|
|
|
158 |
According to the ISO C standard, section 6.3.4, the only legal pointer
|
|
|
159 |
to pointer conversions are explicit conversions between:<P>
|
|
|
160 |
<OL>
|
|
|
161 |
<LI>a pointer to an object or incomplete type and a pointer to a different
|
|
|
162 |
object or incomplete type. The resulting pointer may not be valid
|
|
|
163 |
if it is improperly aligned for the type pointed to;<P>
|
|
|
164 |
<LI>a pointer to a function of one type and a pointer to a function
|
|
|
165 |
of another type. If a converted pointer, used to call a function,
|
|
|
166 |
has a type that is incompatible with the type of the called function,
|
|
|
167 |
the behaviour is undefined.<P>
|
|
|
168 |
</OL>
|
|
|
169 |
Except for conversions to and from the generic pointer which are discussed
|
|
|
170 |
below, all other conversions, including implicit pointer to pointer
|
|
|
171 |
conversions, are extremely unportable. <P>
|
|
|
172 |
All pointer to pointer conversion may be flagged as errors using:<P>
|
|
|
173 |
<PRE>
|
|
|
174 |
#pragma TenDRA conversion analysis ( pointer-pointer ) <EM>status</EM>
|
|
|
175 |
</PRE>
|
|
|
176 |
Explicit and implicit pointer to pointer conversions may be controlled
|
|
|
177 |
separately using:<P>
|
|
|
178 |
<PRE>
|
|
|
179 |
#pragma TenDRA conversion analysis ( pointer-pointer explicit ) <EM>status</EM>
|
|
|
180 |
</PRE>
|
|
|
181 |
and<P>
|
|
|
182 |
<PRE>
|
|
|
183 |
#pragma TenDRA conversion analysis ( pointer-pointer implicit ) <EM>status</EM>
|
|
|
184 |
</PRE>
|
|
|
185 |
where, as before, <CODE>status</CODE> may be <CODE>on</CODE>, <CODE>warning
|
|
|
186 |
</CODE> or <CODE>off</CODE>.<P>
|
|
|
187 |
Conversion between a pointer to a function type and a pointer to a
|
|
|
188 |
non-function type is undefined by the ISO C standard and should generally
|
|
|
189 |
be avoided. The checker can however be configured to treat function
|
|
|
190 |
pointers as object pointers for conversion using:<P>
|
|
|
191 |
<PRE>
|
|
|
192 |
#pragma TenDRA function pointer as pointer <EM>permit</EM>
|
|
|
193 |
</PRE>
|
|
|
194 |
Unless explicitly stated to the contrary, throughout the rest of the
|
|
|
195 |
document where <EM>permit</EM> appears in a pragma statement it represents
|
|
|
196 |
one of <CODE>allow</CODE> (allow the construct and do not produce
|
|
|
197 |
errors), <CODE>warning</CODE> (allow the construct but produce warnings
|
|
|
198 |
when it is detected), or <CODE>disallow</CODE> (produce errors if
|
|
|
199 |
the construct is detected) Here there are three options for <EM>permit</EM>:
|
|
|
200 |
<CODE>allow
|
|
|
201 |
</CODE> (do not produce errors or warnings for function pointer <->
|
|
|
202 |
pointer conversions); <CODE>warning</CODE> (produce a warning when
|
|
|
203 |
function pointer <-> pointer conversions are detected); or <CODE>disallow
|
|
|
204 |
</CODE> (produce an error for function pointer <-> pointer conversions).
|
|
|
205 |
<P>
|
|
|
206 |
The generic pointer, void *, is a special case. All conversions of
|
|
|
207 |
pointers to object or incomplete types to or from a generic pointer
|
|
|
208 |
are allowed. Some older dialects of C used char * as a generic pointer.
|
|
|
209 |
This dialect feature may be allowed, allowed with a warning, or disallowed
|
|
|
210 |
using the pragma:<P>
|
|
|
211 |
<PRE>
|
|
|
212 |
#pragma TenDRA compatible type : char * == void * <EM>permit</EM>
|
|
|
213 |
</PRE>
|
|
|
214 |
where <EM>permit </EM>is <CODE>allow</CODE>, <CODE>warning</CODE>
|
|
|
215 |
or <CODE>disallow</CODE> as before.<P>
|
|
|
216 |
<A NAME=S21>
|
|
|
217 |
<H3>3.2.4 <A NAME=15>Example: 64-bit portability issues</H3>
|
|
|
218 |
64-bit machines form the "next frontier" of program portability.
|
|
|
219 |
Most of the problems involved in 64-bit portability are type conversion
|
|
|
220 |
problems. The assumptions that were safe on a 32-bit machine are not
|
|
|
221 |
necessarily true on a 64-bit machine - int may not be the same size
|
|
|
222 |
as long, pointers may not be the same size as int, and so on. This
|
|
|
223 |
example illustrates the way in which the checker's conversion analysis
|
|
|
224 |
tests can detect potential 64-bit portability problems.<P>
|
|
|
225 |
Consider the following code:<P>
|
|
|
226 |
<PRE>
|
|
|
227 |
#include <stdio.h>
|
|
|
228 |
void print ( string, offset, scale )
|
|
|
229 |
char *string;
|
|
|
230 |
unsigned int offset;
|
|
|
231 |
int scale;
|
|
|
232 |
{
|
|
|
233 |
string += ( scale * offset );
|
|
|
234 |
( void ) puts ( string );
|
|
|
235 |
return;
|
|
|
236 |
}
|
|
|
237 |
|
|
|
238 |
int main ()
|
|
|
239 |
{
|
|
|
240 |
char *s = "hello there";
|
|
|
241 |
print ( s + 4, 2U, -2 );
|
|
|
242 |
return ( 0 );
|
|
|
243 |
}
|
|
|
244 |
</PRE>
|
|
|
245 |
This appears to be fairly simple - the offset of 2U scaled by -2 cancels
|
|
|
246 |
out the offset in s + 4, so the program just prints "hello there".
|
|
|
247 |
Indeed, this is what happens on most machines. When ported to a particular
|
|
|
248 |
64-bit machine, however, it core dumps. The fairly subtle reason is
|
|
|
249 |
that the composite offset, scale * offset, is actually calculated
|
|
|
250 |
as an unsigned int by the ISO C arithmetic conversion rules. So the
|
|
|
251 |
answer is not -4. Strictly speaking it is undefined, but on virtually
|
|
|
252 |
all machines it will be UINT_MAX - 3. The fact that adding this offset
|
|
|
253 |
to string is equivalent to adding -4 is only true on machines on which
|
|
|
254 |
pointers have the same size as unsigned int. If a pointer contains
|
|
|
255 |
64 bits and an unsigned int contains 32 bits, the result is 232 bytes
|
|
|
256 |
out.<P>
|
|
|
257 |
So the error occurs because of the failure to spot that the offset
|
|
|
258 |
being added to string is unsigned. All mixed integer type arithmetic
|
|
|
259 |
involves some argument conversion. In the case above, scale is converted
|
|
|
260 |
to an unsigned int and that is multiplied by offset to give an unsigned
|
|
|
261 |
int result. If the implicit int->int conversion checks (<A HREF="#5">3.2.1
|
|
|
262 |
</A>) are enabled, this conversion is detected and the problem may
|
|
|
263 |
be avoided.<P>
|
|
|
264 |
<A NAME=S22>
|
|
|
265 |
<HR><H2>3.3 <A NAME=17>Function type checking</H2>
|
|
|
266 |
The importance of function type checking in C lies in the conversions
|
|
|
267 |
which can result from type mismatches between the arguments in a function
|
|
|
268 |
call and the parameter types assumed by its definition or between
|
|
|
269 |
the specified type of the function return and the values returned
|
|
|
270 |
within the function definition. Until the introduction of function
|
|
|
271 |
prototypes into ISO standard C, there was little scope for detecting
|
|
|
272 |
the correct typing of functions. Traditional C allows for absolutely
|
|
|
273 |
no type checking of function arguments, so that totally bizarre functions,
|
|
|
274 |
such as:<P>
|
|
|
275 |
<PRE>
|
|
|
276 |
int f ( n ) int n ; {
|
|
|
277 |
return ( f ( "hello", "there" ) ) ;
|
|
|
278 |
}
|
|
|
279 |
</PRE>
|
|
|
280 |
are allowed, although their effect is undefined. However, the move
|
|
|
281 |
to fully prototyped programs has been relatively slow. This is partially
|
|
|
282 |
due to an understandable reluctance to change existing, working programs,
|
|
|
283 |
but the desire to maintain compatibility with existing C compilers,
|
|
|
284 |
some of which still do not support prototypes, is also a powerful
|
|
|
285 |
factor. Prototypes are allowed in the checker's default mode but tchk
|
|
|
286 |
can be configured to allow, allow with a warning or disallow prototypes,
|
|
|
287 |
using:<P>
|
|
|
288 |
<PRE>
|
|
|
289 |
#pragma TenDRA prototype <EM>permit</EM>
|
|
|
290 |
</PRE>
|
|
|
291 |
where <EM>permit </EM>is <CODE>allow</CODE>, <CODE>disallow</CODE>
|
|
|
292 |
or <CODE>warning</CODE>. <P>
|
|
|
293 |
Even if prototypes are not supported the checker has a facility, described
|
|
|
294 |
below, for detecting incorrectly typed functions.<P>
|
|
|
295 |
<A NAME=S23>
|
|
|
296 |
<H3>3.3.1 <A NAME=20>Type checking non-prototyped functions</H3>
|
|
|
297 |
The checker offers a method for applying prototype-like checks to
|
|
|
298 |
traditionally defined functions, by introducing the concept of "
|
|
|
299 |
weak" prototypes. A weak prototype contains function parameter
|
|
|
300 |
type information, but has none of the automatic argument conversions
|
|
|
301 |
associated with a normal prototype. Instead weak prototypes imply
|
|
|
302 |
the usual argument promotion passing rules for non-prototyped functions.
|
|
|
303 |
The type information required for a weak prototype can be obtained
|
|
|
304 |
in three ways:<P>
|
|
|
305 |
<OL>
|
|
|
306 |
<LI>A weak prototype may be declared using the syntax:<P>
|
|
|
307 |
<PRE>
|
|
|
308 |
int f <EM>WEAK</EM> ( char, char * ) ;
|
|
|
309 |
</PRE>
|
|
|
310 |
where<EM> WEAK</EM> represents any keyword which has been introduced
|
|
|
311 |
using:<P>
|
|
|
312 |
<PRE>
|
|
|
313 |
#pragma TenDRA keyword <EM>WEAK</EM> for weak
|
|
|
314 |
</PRE>
|
|
|
315 |
An alternative definition of the keyword must be provided for other
|
|
|
316 |
compilers. For example, the following definition would make system
|
|
|
317 |
compilers interpret weak prototypes as normal (strong) prototypes:<P>
|
|
|
318 |
<PRE>
|
|
|
319 |
#ifdef __TenDRA__
|
|
|
320 |
#pragma TenDRA keyword WEAK for weak
|
|
|
321 |
#else
|
|
|
322 |
#define WEAK
|
|
|
323 |
#endif
|
|
|
324 |
</PRE>
|
|
|
325 |
The difference between conventional prototypes and weak prototypes
|
|
|
326 |
can be illustrated by considering the normal prototype for f:
|
|
|
327 |
<PRE>
|
|
|
328 |
int f (char,char *);
|
|
|
329 |
</PRE>
|
|
|
330 |
When the prototype is present, the first argument to f would be passed
|
|
|
331 |
as a char. Using the weak prototype, however, results in the first
|
|
|
332 |
argument being passed as the integral promotion of char, that is to
|
|
|
333 |
say, as an int.<P>
|
|
|
334 |
There is one limitation on the declaration of weak prototypes - declarations
|
|
|
335 |
of the form:
|
|
|
336 |
<PRE>
|
|
|
337 |
int f <EM>WEAK</EM>() ;
|
|
|
338 |
</PRE>
|
|
|
339 |
are not allowed. If a function has no arguments, this should be stated
|
|
|
340 |
explicitly as:<P>
|
|
|
341 |
<PRE>
|
|
|
342 |
int f <EM>WEAK</EM>( void ) ;
|
|
|
343 |
</PRE>
|
|
|
344 |
whereas if the argument list is not specified, weak prototypes should
|
|
|
345 |
be avoided and a traditional declaration used instead:<P>
|
|
|
346 |
<PRE>
|
|
|
347 |
extern int f ();
|
|
|
348 |
</PRE>
|
|
|
349 |
The checker may be configured to allow, allow with a warning or disallow
|
|
|
350 |
weak prototype declarations using:
|
|
|
351 |
<PRE>
|
|
|
352 |
#pragma TenDRA prototype ( weak ) <EM>permit</EM>
|
|
|
353 |
</PRE>
|
|
|
354 |
where <CODE>permit</CODE> is replaced by <CODE>allow</CODE>, <CODE>warning
|
|
|
355 |
</CODE> or <CODE>disallow</CODE> as appropriate. Weak prototypes are
|
|
|
356 |
not permitted in the default mode.<P>
|
|
|
357 |
<LI>Information can be deduced from a function definition. For example,
|
|
|
358 |
the function definition:<P>
|
|
|
359 |
<PRE>
|
|
|
360 |
int f(c,s) char c; char *s;{...}
|
|
|
361 |
</PRE>
|
|
|
362 |
is said to have weak prototype:<P>
|
|
|
363 |
<PRE>
|
|
|
364 |
int f <EM>WEAK</EM> (char,char *);
|
|
|
365 |
</PRE>
|
|
|
366 |
The checker automatically constructs a weak prototype for each traditional
|
|
|
367 |
function definition it encounters and if the weak prototype analysis
|
|
|
368 |
mode is enabled (see below) all subsequent calls of the function are
|
|
|
369 |
checked against this weak prototype. <P>
|
|
|
370 |
For example, in the bizarre function in <A HREF="#17">3.3</A>, the
|
|
|
371 |
weak prototype:<P>
|
|
|
372 |
<PRE>
|
|
|
373 |
int f <EM>WEAK</EM> ( int );
|
|
|
374 |
</PRE>
|
|
|
375 |
is constructed for f. The subsequent call to f:<P>
|
|
|
376 |
<PRE>
|
|
|
377 |
f ( "hello", "there" );
|
|
|
378 |
</PRE>
|
|
|
379 |
is then rejected by comparison with this weak prototype - not only
|
|
|
380 |
is f called with the wrong number of arguments, but the first argument
|
|
|
381 |
has a type incompatible with (the integral promotion of) int.<P>
|
|
|
382 |
<LI>Information may be deduced from the calls of a function. For example,
|
|
|
383 |
in:<P>
|
|
|
384 |
<PRE>
|
|
|
385 |
extern void f ();
|
|
|
386 |
void g ()
|
|
|
387 |
{
|
|
|
388 |
f ( 3 );
|
|
|
389 |
f ( "hello" );
|
|
|
390 |
}
|
|
|
391 |
</PRE>
|
|
|
392 |
we can infer from the first call of f that f takes one integral argument.
|
|
|
393 |
We cannot deduce the type of this argument, only that it is an integral
|
|
|
394 |
type whose promotion is int (since this is how the argument is passed).
|
|
|
395 |
We can therefore infer a partial weak prototype for f:<P>
|
|
|
396 |
<PRE>
|
|
|
397 |
void f <EM>WEAK</EM> ( t );
|
|
|
398 |
</PRE>
|
|
|
399 |
for some integral type t which promotes to int. Similarly, from the
|
|
|
400 |
second call of f we can infer the weak prototype:<P>
|
|
|
401 |
<PRE>
|
|
|
402 |
void f <EM>WEAK</EM> ( char * );
|
|
|
403 |
</PRE>
|
|
|
404 |
(the argument passing rules are much simpler in this case). Clearly
|
|
|
405 |
the two inferred prototypes are incompatible, so an error is raised.<P>
|
|
|
406 |
Note that prototype inferred from function calls alone cannot ensure
|
|
|
407 |
that the uses of the function within a source file are correct, merely
|
|
|
408 |
that they are consistent. The presence of an explicit function declaration
|
|
|
409 |
or definition is required for a definitive "right" prototype.<P>
|
|
|
410 |
Null pointers cause particular problems with weak prototypes inferred
|
|
|
411 |
from function calls. For example, in:<P>
|
|
|
412 |
<PRE>
|
|
|
413 |
#include <stdio.h>
|
|
|
414 |
extern void f ();
|
|
|
415 |
void g () {
|
|
|
416 |
f ( "hello" );
|
|
|
417 |
f( NULL );
|
|
|
418 |
}<P>
|
|
|
419 |
</PRE>
|
|
|
420 |
the argument in the first call of f is char* whereas in the second
|
|
|
421 |
it is int (because NULL is defined to be 0). Whereas NULL can be converted
|
|
|
422 |
to char*, it is not necessarily passed to procedures in the same way
|
|
|
423 |
(for example, it may be that pointers have 64 bits and ints have 32
|
|
|
424 |
bits). It is almost always necessary to cast NULL to the appropriate
|
|
|
425 |
pointer type in weak procedure calls.<P>
|
|
|
426 |
</OL>
|
|
|
427 |
Functions for which explicitly declared weak prototypes are provided
|
|
|
428 |
are always type-checked by the checker. Weak prototypes deduced from
|
|
|
429 |
function declarations or calls are used for type checking if the weak
|
|
|
430 |
prototype analysis mode is enabled using:<P>
|
|
|
431 |
<PRE>
|
|
|
432 |
#pragma TenDRA weak prototype analysis <EM>status</EM>
|
|
|
433 |
</PRE>
|
|
|
434 |
where <CODE>status</CODE> is one of <CODE>on</CODE>, <CODE>warning</CODE>
|
|
|
435 |
and <CODE>off</CODE> as usual. Weak prototype analysis is not performed
|
|
|
436 |
in the default mode.<P>
|
|
|
437 |
There is also an equivalent command line option of the form <CODE>-X:weak_proto=
|
|
|
438 |
</CODE><CODE>state</CODE>, where <CODE>state</CODE> can be <CODE>check</CODE>,
|
|
|
439 |
<CODE>warn</CODE> or <CODE>dont</CODE>. <P>
|
|
|
440 |
This section ends with two examples which demonstrate some of the
|
|
|
441 |
less obvious consequences of weak prototype analysis.<P>
|
|
|
442 |
<P>
|
|
|
443 |
<B>Example 1: An obscure type mismatch</B><P>
|
|
|
444 |
As stated above, the promotion and conversion rules for weak prototypes
|
|
|
445 |
are precisely those for traditionally declared and defined functions.
|
|
|
446 |
Consider the program:<P>
|
|
|
447 |
<PRE>
|
|
|
448 |
void f ( n )long n;{
|
|
|
449 |
printf ( "%ld\n", n );
|
|
|
450 |
}
|
|
|
451 |
void g (){
|
|
|
452 |
f ( 3 );
|
|
|
453 |
}
|
|
|
454 |
</PRE>
|
|
|
455 |
The literal constant 3 is an int and hence is passed as such to f.
|
|
|
456 |
f is however expecting a long, which can lead to problems on some
|
|
|
457 |
machines. Introducing a strong prototype declaration of f for those
|
|
|
458 |
compilers which understand them:<P>
|
|
|
459 |
<PRE>
|
|
|
460 |
#ifdef __STDC__
|
|
|
461 |
void f ( long );
|
|
|
462 |
#endif
|
|
|
463 |
</PRE>
|
|
|
464 |
will produce correct code - the arguments to a function declared with
|
|
|
465 |
a prototype are converted to the appropriate types, so that the literal
|
|
|
466 |
is actually passed as 3L. This solves the problem for compilers which
|
|
|
467 |
understand prototypes, but does not actually detect the underlying
|
|
|
468 |
error. Weak prototypes, because they use the traditional argument
|
|
|
469 |
passing rules, do detect the error. The constructed weak prototype:<P>
|
|
|
470 |
<PRE>
|
|
|
471 |
void f <EM>WEAK</EM> ( long );
|
|
|
472 |
</PRE>
|
|
|
473 |
conveys the type information that f is expecting a long, but accepts
|
|
|
474 |
the function arguments as passed rather than converting them. Hence,
|
|
|
475 |
the error of passing an int argument to a function expecting a long
|
|
|
476 |
is detected.<P>
|
|
|
477 |
Many programs, seeking to have prototype checks while preserving compilability
|
|
|
478 |
with non-prototype compilers, adopt a compromise approach of traditional
|
|
|
479 |
definitions plus prototype declarations for those compilers which
|
|
|
480 |
understand them, as in the example above. While this ensures correct
|
|
|
481 |
argument passing in the prototype case, as the example shows it may
|
|
|
482 |
obscure errors in the non-prototype case.<P>
|
|
|
483 |
<P>
|
|
|
484 |
<B>Example 2: Weak prototype checks in defined programs</B><P>
|
|
|
485 |
In most cases a program which fails to compile with the weak prototype
|
|
|
486 |
analysis enabled is undefined. ISO standard C does however contain
|
|
|
487 |
an anomalous rule on equivalence of representation. For example, in:<P>
|
|
|
488 |
<PRE>
|
|
|
489 |
extern void f ();
|
|
|
490 |
void g () {
|
|
|
491 |
f ( 3 );
|
|
|
492 |
f ( 4U );
|
|
|
493 |
}
|
|
|
494 |
</PRE>
|
|
|
495 |
the TenDRA checker detects an error - in one instance f is being passed
|
|
|
496 |
an int, whereas in the other it is being passed an unsigned int. However,
|
|
|
497 |
the ISO C standard states that, for values which fit into both types,
|
|
|
498 |
the representation of a number as an int is equal to that as an unsigned
|
|
|
499 |
int, and that values with the same representation are interchangeable
|
|
|
500 |
in procedure arguments. Thus the program is defined. The justification
|
|
|
501 |
for raising an error or warning for this program is that the prototype
|
|
|
502 |
analysis is based on types, not some weaker notion of "equivalence
|
|
|
503 |
of representation". The program may be defined, but it is not
|
|
|
504 |
type correct.<P>
|
|
|
505 |
Another case in which a program is defined, but not correct, is where
|
|
|
506 |
an unnecessary extra argument is passed to a function. For example,
|
|
|
507 |
in:<P>
|
|
|
508 |
<PRE>
|
|
|
509 |
void f ( a ) int a; {
|
|
|
510 |
printf ( "%d\n", a );
|
|
|
511 |
}
|
|
|
512 |
void g () {
|
|
|
513 |
f ( 3, 4 );
|
|
|
514 |
}
|
|
|
515 |
</PRE>
|
|
|
516 |
the call of f is defined, but is almost certainly a mistake.<P>
|
|
|
517 |
<A NAME=S24>
|
|
|
518 |
<H3>3.3.2 <A NAME=23>Checking printf strings
|
|
|
519 |
</H3>
|
|
|
520 |
Normally functions which take a variable number of arguments offer
|
|
|
521 |
only limited scope for type checking. For example, given the prototype:<P>
|
|
|
522 |
<PRE>
|
|
|
523 |
int execl ( const char *, const char *, ... );
|
|
|
524 |
</PRE>
|
|
|
525 |
the first two arguments may be checked, but we have no hold on any
|
|
|
526 |
subsequent arguments (in fact in this example they should all be const
|
|
|
527 |
char *, but C does not allow this information to be expressed). Two
|
|
|
528 |
classes of functions of this form, namely the printf and scanf families,
|
|
|
529 |
are so common that they warrant special treatment. If one of these
|
|
|
530 |
functions is called with a constant format string, then it is possible
|
|
|
531 |
to use this string to deduce the types of the extra arguments that
|
|
|
532 |
it is expect ing. For example, in:<P>
|
|
|
533 |
<PRE>
|
|
|
534 |
printf ( "%ld", 4 );
|
|
|
535 |
</PRE>
|
|
|
536 |
the format string indicates that printf is expecting a single additional
|
|
|
537 |
argument of type long. We can therefore deduce a <EM>quasi-prototype</EM>
|
|
|
538 |
which this particular call to printf should conform to, namely:<P>
|
|
|
539 |
<PRE>
|
|
|
540 |
int printf ( const char *,long );
|
|
|
541 |
</PRE>
|
|
|
542 |
In fact this is a mixture of a strong prototype and a weak prototype.
|
|
|
543 |
The first argument comes from the actual prototype of printf, and
|
|
|
544 |
hence is strong. All subsequent arguments correspond to the ellipsis
|
|
|
545 |
part of the printf prototype, and are passed by the normal promotion
|
|
|
546 |
rules. Hence the long component of the inferred prototype is weak
|
|
|
547 |
(see 3.3.1). This means that the error in the call to printf - the
|
|
|
548 |
integer literal is passed as an int when a long is expected - is detected.<P>
|
|
|
549 |
In order for this check to take place, the function declaration needs
|
|
|
550 |
to tell the checker that the function is like printf. This is done
|
|
|
551 |
by introducing a special type, <EM>PSTRING</EM> say, to stand for
|
|
|
552 |
a printf string, using:<P>
|
|
|
553 |
<PRE>
|
|
|
554 |
#pragma TenDRA type <EM>PSTRING</EM> for ... printf
|
|
|
555 |
</PRE>
|
|
|
556 |
For most purposes this is equivalent to:<P>
|
|
|
557 |
<PRE>
|
|
|
558 |
typedef const char *<EM>PSTRING</EM>;
|
|
|
559 |
</PRE>
|
|
|
560 |
except that when a function declaration:<P>
|
|
|
561 |
<PRE>
|
|
|
562 |
int f ( <EM>PSTRING</EM>, ... );
|
|
|
563 |
</PRE>
|
|
|
564 |
is encountered the checker knows to deduce the types of the arguments
|
|
|
565 |
corresponding to the ... from the PSTRING argument (the precise rules
|
|
|
566 |
it applies are those set out in the XPG4 definition of fprintf). If
|
|
|
567 |
this mechanism is used to apply printf style checks to user defined
|
|
|
568 |
functions, an alternative definition of PSTRING for conventional compilers
|
|
|
569 |
must be provided. For example:<P>
|
|
|
570 |
<PRE>
|
|
|
571 |
#ifdef __TenDRA__
|
|
|
572 |
#pragma TenDRA type PSTRING for ... printf
|
|
|
573 |
#else
|
|
|
574 |
typedef const char *PSTRING;
|
|
|
575 |
#endif
|
|
|
576 |
</PRE>
|
|
|
577 |
There are similar rules with scanf in place of printf.<P>
|
|
|
578 |
The TenDRA descriptions of the standard APIs use this mechanism to
|
|
|
579 |
describe those functions, namely printf, fprintf and sprintf, and
|
|
|
580 |
scanf, fscanf and sscanf which are of these forms. This means that
|
|
|
581 |
the checks are switched on for these functions by default. However,
|
|
|
582 |
these descriptions are under the control of a macro, __NO_PRINTF_CHECKS,
|
|
|
583 |
which, if defined before stdio.h is included, effectively switches
|
|
|
584 |
the checks off. This macro is defined in the start-up files for certain
|
|
|
585 |
checking modes, so that the checks are disabled in these modes (see
|
|
|
586 |
chapter 2). The checks can be enabled in these cases by #undef'ing
|
|
|
587 |
the macro before including stdio.h. There are equivalent command-line
|
|
|
588 |
options to tchk of the form <CODE>-X:printf=</CODE><CODE>state</CODE>,
|
|
|
589 |
where <CODE>state</CODE> can be <CODE>check</CODE> or <CODE>dont</CODE>,
|
|
|
590 |
which respectively undefine and define this macro.<P>
|
|
|
591 |
<A NAME=S25>
|
|
|
592 |
<H3>3.3.3 <A NAME=25>Function return checking
|
|
|
593 |
</H3>
|
|
|
594 |
Function returns normally present no difficulties. The return value
|
|
|
595 |
is converted, as if by assignment, to the function return type, so
|
|
|
596 |
that the problem is essentially one of type conversion (see 3.2).
|
|
|
597 |
There is however one anomalous case. A plain return statement, without
|
|
|
598 |
a return value, is allowed in functions returning a non-void type,
|
|
|
599 |
the value returned being undefined. For example, in:<P>
|
|
|
600 |
<PRE>
|
|
|
601 |
int f ( int c )
|
|
|
602 |
{
|
|
|
603 |
if ( c ) return ( 1 );
|
|
|
604 |
return;
|
|
|
605 |
}
|
|
|
606 |
</PRE>
|
|
|
607 |
the value returned when c is zero is undefined. The test for detecting
|
|
|
608 |
such void returns is controlled by:<P>
|
|
|
609 |
<PRE>
|
|
|
610 |
#pragma TenDRA incompatible void return <EM>permit</EM>
|
|
|
611 |
</PRE>
|
|
|
612 |
where <EM>permit</EM> may be <CODE>allow</CODE>, <CODE>warning</CODE>
|
|
|
613 |
or <CODE>disallow</CODE> as usual. <P>
|
|
|
614 |
There are also equivalent command line options to tchk of the form
|
|
|
615 |
<CODE>-X:void_ret=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
|
|
|
616 |
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.
|
|
|
617 |
Incompatible void returns are allowed in the default mode and of course,
|
|
|
618 |
plain return statements in functions returning void are always legal.<P>
|
|
|
619 |
This check also detects functions which do not contain a return statement,
|
|
|
620 |
but fall out of the bottom of the function as in:<P>
|
|
|
621 |
<PRE>
|
|
|
622 |
int f ( int c )
|
|
|
623 |
{
|
|
|
624 |
if ( c ) return ( 1 );
|
|
|
625 |
}
|
|
|
626 |
</PRE>
|
|
|
627 |
Occasionally it may be the case that such a function is legal, because
|
|
|
628 |
the end of the function is not reached. Unreachable code is discussed
|
|
|
629 |
in section <A HREF="tdfc8.html#2">5.2</A>.<P>
|
|
|
630 |
<A NAME=S26>
|
|
|
631 |
<HR><H2>3.4 Overriding type checking</H2>
|
|
|
632 |
There are several commonly used features of C, some of which are even
|
|
|
633 |
allowed by the ISO C standard, which can circumvent or hinder the
|
|
|
634 |
type-checking of a program. The checker may be configured either to
|
|
|
635 |
enforce the absence of these features or to support them with or without
|
|
|
636 |
a warning, as described below.<P>
|
|
|
637 |
<A NAME=S27>
|
|
|
638 |
<H3>3.4.1 <A NAME=30>Implicit Function Declarations
|
|
|
639 |
</H3>
|
|
|
640 |
The ISO C standard states that any undeclared function is implicitly
|
|
|
641 |
assumed to return int. For example, in ISO C:<P>
|
|
|
642 |
<PRE>
|
|
|
643 |
int f ( int c ) {
|
|
|
644 |
return ( g( c )+1 );
|
|
|
645 |
}
|
|
|
646 |
</PRE>
|
|
|
647 |
the undeclared function g is inferred to have a declaration:<P>
|
|
|
648 |
<PRE>
|
|
|
649 |
extern int g ();
|
|
|
650 |
</PRE>
|
|
|
651 |
This can potentially lead to program errors. The definition of f would
|
|
|
652 |
be valid if g actually returned double, but incorrect code would be
|
|
|
653 |
produced. Again, an explicit declaration might give us more information
|
|
|
654 |
about the function argument types, allowing more checks to be applied.<P>
|
|
|
655 |
Therefore the best chance of detecting bugs in a program and ensuring
|
|
|
656 |
its portability comes from having each function declared before it
|
|
|
657 |
is used. This means detecting implicit declarations and replacing
|
|
|
658 |
them by explicit declarations. By default implicit function declarations
|
|
|
659 |
are allowed, however the pragma:<P>
|
|
|
660 |
<PRE>
|
|
|
661 |
#pragma TenDRA implicit function declaration <EM>status</EM>
|
|
|
662 |
</PRE>
|
|
|
663 |
may be used to determine how tchk handles implicit function declarations.
|
|
|
664 |
<CODE>Status</CODE> is replaced by <CODE>on</CODE> to allow implicit
|
|
|
665 |
declarations, <CODE>warning</CODE> to allow implicit declarations
|
|
|
666 |
but to produce a warning when they occur, or <CODE>off</CODE> to prevent
|
|
|
667 |
implicit declarations and raise an error where they would normally
|
|
|
668 |
be used.<P>
|
|
|
669 |
(There are also equivalent command-line options to tcc of the form
|
|
|
670 |
<CODE>-X:implicit_func=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
|
|
|
671 |
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.)<P>
|
|
|
672 |
This test assumes an added significance in API checking. If a programmer
|
|
|
673 |
wishes to check that a certain program uses nothing outside the POSIX
|
|
|
674 |
API, then implicitly declared functions are a potential danger area.
|
|
|
675 |
A function from outside POSIX could be used without being detected
|
|
|
676 |
because it has been implicitly declared. Therefore, the detection
|
|
|
677 |
of implicitly declared functions is vital to rigorous API checking.<P>
|
|
|
678 |
<A NAME=S28>
|
|
|
679 |
<H3>3.4.2 <A NAME=32>Function Parameters</H3>
|
|
|
680 |
Many systems pass function arguments of differing types in the same
|
|
|
681 |
way and programs are sometimes written to take advantage of this feature.
|
|
|
682 |
The checker has a number of options to resolve type mismatches which
|
|
|
683 |
may arise in this way and would otherwise be flagged as errors:<P>
|
|
|
684 |
<OL>
|
|
|
685 |
<LI><B>Type-type compatibility</B><P>
|
|
|
686 |
When comparing function prototypes for compatibility, the function
|
|
|
687 |
parameter types must be compared. If the parameter types would otherwise
|
|
|
688 |
be incompatible, they are treated as compatible if they have previously
|
|
|
689 |
been introduced with a type-type param ter compatibility pragma i.e.<P>
|
|
|
690 |
<PRE>
|
|
|
691 |
#pragma TenDRA argument <EM>type-name</EM> as <EM>type-name</EM>
|
|
|
692 |
</PRE>
|
|
|
693 |
where <EM>type-name</EM> is the name of any type. This pragma is transitive
|
|
|
694 |
and the second type in the pragma is taken to be the final type of
|
|
|
695 |
the parameter. <P>
|
|
|
696 |
<LI><B>Type-ellipsis compatibility</B><P>
|
|
|
697 |
Two function prototypes with different numbers of arguments are compatible
|
|
|
698 |
if: <P>
|
|
|
699 |
<UL>
|
|
|
700 |
<LI>both prototypes have an ellipsis; <P>
|
|
|
701 |
<LI>each parameter type common to both prototypes is compatible;<P>
|
|
|
702 |
<LI>each extra parameter type in the prototype with more parameters,
|
|
|
703 |
is either specified in a type-ellipsis compatibility pragma or is
|
|
|
704 |
type-type compatible (see above) to a type that is specified in a
|
|
|
705 |
type-ellipsis compatibility.<P>
|
|
|
706 |
</UL>
|
|
|
707 |
Type-ellipsis compatibility is introduced using the pragma: <P>
|
|
|
708 |
<PRE>
|
|
|
709 |
#pragma TenDRA argument <EM>type-name</EM> as ...
|
|
|
710 |
</PRE>
|
|
|
711 |
where again <CODE>type-name</CODE> is the name of any type.<P>
|
|
|
712 |
<LI><B>Ellipsis compatibility</B><P>
|
|
|
713 |
If, when comparing two function prototypes for compatibility, one
|
|
|
714 |
has an ellipsis and the other does not, but otherwise the two types
|
|
|
715 |
would be compatible, then if an `extra' ellipsis is allowed, the types
|
|
|
716 |
are treated as compatible. The pragma controlling ellipsis compatibility
|
|
|
717 |
is:<P>
|
|
|
718 |
<PRE>
|
|
|
719 |
#pragma TenDRA extra ... <EM>permit</EM>
|
|
|
720 |
</PRE>
|
|
|
721 |
where <CODE>permit</CODE> may be <CODE>allow</CODE>, <CODE>disallow</CODE>
|
|
|
722 |
or <CODE>warning</CODE> as usual. <P>
|
|
|
723 |
</OL>
|
|
|
724 |
<P>
|
|
|
725 |
<P>
|
|
|
726 |
<A NAME=S29>
|
|
|
727 |
<H3>3.4.3 <A NAME=37>Incompatible promoted function arguments</H3>
|
|
|
728 |
Mixing the use of prototypes with old-fashioned function definitions
|
|
|
729 |
can result in incorrect code. For example, in the program below the
|
|
|
730 |
function argument promotion rules are applied to the definition of
|
|
|
731 |
f, making it incompatible with the earlier prototype (a is converted
|
|
|
732 |
to the integer promotion of char, i.e. int).<P>
|
|
|
733 |
<PRE>
|
|
|
734 |
int f(char);
|
|
|
735 |
int f(a)char a;{
|
|
|
736 |
...
|
|
|
737 |
}
|
|
|
738 |
</PRE>
|
|
|
739 |
An incompatible type error is raised in the default checking mode.
|
|
|
740 |
The check for incompatible types which arise from mixtures of prototyped
|
|
|
741 |
and non-prototyped function declarations and definitions is controlled
|
|
|
742 |
using: <P>
|
|
|
743 |
<CODE>#pragma TenDRA incompatible promoted function argument </CODE><EM>permit
|
|
|
744 |
</EM><P>
|
|
|
745 |
<CODE>Permit</CODE> may be replaced by <CODE>allow</CODE>, <CODE>warning</CODE>
|
|
|
746 |
or <CODE>disallow</CODE> as normal. The parameter type in the resulting
|
|
|
747 |
function type is the promoted parameter type.<P>
|
|
|
748 |
<A NAME=S30>
|
|
|
749 |
<H3>3.4.4 <A NAME=39>Incompatible type qualifiers</H3>
|
|
|
750 |
The declarations <P>
|
|
|
751 |
<PRE>
|
|
|
752 |
const int a;
|
|
|
753 |
int a;
|
|
|
754 |
</PRE>
|
|
|
755 |
are not compatible according to the ISO C standard because the qualifier,
|
|
|
756 |
const, is present in one declaration but not in the other. Similar
|
|
|
757 |
rules hold for volatile qualified types. By default, tchk produces
|
|
|
758 |
an error when declarations of the same object contain different type
|
|
|
759 |
qualifiers. The check is controlled using: <P>
|
|
|
760 |
<PRE>
|
|
|
761 |
#pragma TenDRA incompatible type qualifier <EM>permit</EM>
|
|
|
762 |
</PRE>
|
|
|
763 |
where the options for <EM>permit</EM> are <CODE>allow</CODE>, <CODE>disallow
|
|
|
764 |
</CODE> or <CODE>warning</CODE>.<P>
|
|
|
765 |
<P>
|
|
|
766 |
<!-- FM pgf ignored -->
|
|
|
767 |
<HR>
|
|
|
768 |
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
|
|
|
769 |
Copyright © 1998.</I></P>
|
|
|
770 |
</BODY>
|
|
|
771 |
</HTML>
|