Another linkage problem, which is left undefined in the ISO C standard,
is illustrated by the following program:
A more common feature, allowed by the ISO C standard, but considered
bad style by some, is the inference of an int return type for functions
defined in the form:
If non-int bitfields are allowed, the bitfield is treated as if it
had been declared with an int type of the same signedness as the given
type. The use of the type char as a bitfield type still generally
causes an error, since whether a plain char is treated as signed or
unsigned is implementation-dependent. The pragma:
Part of the TenDRA Web.7.2 Resolving linkage problems
Often the way that identifier names are resolved can alter the semantics
of a program. For example, in:
void f () {
{
extern void g ();
g ( 3 );
}
g ( 7 );
}
the external declaration of g is only in scope in the inner block
of f. Thus, at the second call of g, it is not in scope, and so is
inferred to have declaration:
extern int g ();
(see 3.4). This conflicts with the previous declaration of g which,
although not in scope, has been registered in the external namespace.
The pragma:
#pragma TenDRA unify external linkage on
modifies the algorithm for resolving external linkage by searching
the external namespace before inferring a declaration. In the example
above, this results in the second use of g being resolved to the previous
external declaration. The on
can be replaced by warning
to give a warning when such resolutions are detected, or off
to switch this feature off.
int f () {
extern int g ();
return ( g () );
}
static int g ()
{
return ( 0 );
}
Is the external variable g (the declaration of which would be inferred
if it was omitted) the same as the static variable g? Of course, had
the order of the two functions been reversed, there would be no doubt
that they were, however, in the given case it is undefined. By default,
the linkage is resolved externally, so that the two uses of g are
not identified. However, the checker can be made to resolve its linkage
internally, so that the two uses of g are identified. The resolution
algorithm can be set using:
#pragma TenDRA linkage resolution : action
where action
can be one of:
depending on whether the linkage resolution is internal, external,
or default, and whether a warning message is required. The most useful
behaviour is to issue a warning for all such occurrences (by setting
action to (internal) warning, for example) so that the programmer
can be alerted to clarify what was intended.(internal) on
(internal) warning
(external) on
(external) warning
off
7.3 Identifier linkage
The ISO C standard, section 6.1.2.2, states that "if, within
a translation unit, an identifier appears with both internal and external
linkage, the behaviour is undefined". By default, the checker
silently declares the variable with external linkage. The check to
detect variables which are redeclared with incompatible linkage is
controlled using:
#pragma TenDRA incompatible linkage permit
where permit
may be allow
(default mode), warning
(warn about incompatible linkage)
or disallow
(raise errors for redeclarations with incompatible
linkage).7.4 Implicit integer types
Older C dialects allow external variables to be specified without
a type, the type int being inferred. Thus, for example:
a, b;
is equivalent to:
int a, b;
By default these inferred declarations are not permitted, though tchk's
behaviour can be modified using:
#pragma TenDRA implicit int type for external declaration permit
where permit is allow
, warning
or disallow
.
f ( int n ) {
....
}
the checker's treatment of such functions can be determined using:
#pragma TenDRA implicit int type for function return permit
where permit
can be allow
, warning
or disallow
.7.5 Bitfield types
The ISO C standard only allows signed int, unsigned int and their
equivalent types as type specifiers in bitfields. Using the default
checking profile, tchk raises errors for other integral types used
as type specifiers in bitfields.This behaviour may be modified using
the pragma:
#pragma TenDRA extra int bitfield type permit
Permit
is one of allow
(no errors raised),
warning
(allow non-int bitfields through with a warning)
or disallow
(raise errors for non-int bitfields).
#pragma TenDRA character set-sign
where set-sign
is signed
, unsigned
or either
, can be used to specify the signedness of a
plain char bitfield. If set-sign is signed
or
unsigned
, the bitfield is treated as though it were declared
signed char or unsigned char respectively. If set-sign is
either
, the sign of the bitfield is target-dependent
and the use of a plain char bitfield causes an error.7.6 Extra type definitions
In accordence with the ISO C standard, in default mode tchk does not
allow a type to be defined more than once using a typedef. The pragma:
#pragma TenDRA extra type definition permit
where permit
is allow
(silently accepts
redefinitions, provided they are consistent), warning
or disallow
.7.7 Static block level functions
The ISO C standard (Section 6.5.1) states that the declaration of
an identifier for a function that has block scope shall have no explicit
storage-class specifier other than extern. By default, tchk raises
an error for declarations which do not conform to this rule. The behaviour
can be modified using:
#pragma TenDRA block function static permit
where permit
is allow
(accept block scope
function declarations with other storage-class specifiers), disallow
or warning
. 7.8 Incomplete array element types
The ISO C standard (Section 6.1.2.5) states that an incomplete type
e.g an undefined structure or union type, is not an object type and
that array elements must be of object type. The default behaviour
of the checker causes errors when incomplete types are used to specify
array element types. The pragma:
#pragma TenDRA incomplete type as object type permit
can be used to alter the treatment of array declarations with incomplete
element types. Permit is one of allow
, disallow
or warning
as usual.7.9 Forward enumeration declarations
The ISO C Standard (Section 6.5.2.3) states that the first introduction
of an enumeration tag shall declare the constants associated with
that tag. This rule is enforced by the checker in default mode, however
it can be relaxed using the pragma:
#pragma TenDRA forward enum declaration permit
where replacing permit
by allow
permits
the declaration and use of an enumeration tag before the declaration
of its associated enumeration constants. A disallow
variant
which restores the default behaviour is also available.7.10 Untagged compound types
The ISO C standard states that a declaration must declare at least
a declarator, a tag or the members of an enumeration. The checker
detects such declarations and, by default, raises an error. The severity
of the errors can be altered by:
#pragma TenDRA unknown struct/union permit
where permit
may be allow
to allows code
such as:
struct {int i; int j;};
through without errors (statements such as this occur in some system
headers) or disallow
to restore the default behaviour.7.11 External volatility
The inclusion of the pragma:
#pragma TenDRA external volatile_t
instructs the checker thereafter to treat any object declared with
external linkage (ISO C standard Section 6.1.2.2) as if it were volatile
(ISO C standard Section 6.5.3). This was a feature of some traditional
C dialects. In the default mode, objects with external linkage are
only treated as volatile if they were declared with the volatile type
qualifier.7.12 Identifier name length
Under the ISO C standard rules on identifier name length, an implementation
is only required to treat the first 31 characters of an internal name
and the first 6 characters of an external name as significant. The
TenDRA C checker provides a facility for users to specify the maximum
number of characters allowed in an identifier name, to prevent unexpected
results when the application is moved to a new implementation. The
limit is set using:
#pragma TenDRA set name limit integer_constant
There is currently no distinction made between external and internal
names for length checking. Identifier name lengths are not checked
in the default mode.7.13 Ellipsis in function calls
An ellipsis is not an identifier and should not be used in a function
call, even if, as in the program below, the function prototype contains
an ellipsis:
int f(int a,...) {
return 1; }
int main() {
int x, y;
x=f(y ,...);
return 1;
}
In default mode the checker raises an error if an ellipsis is used
as a parameter in a function call. The severity of this error can
be modified by using:
#pragma TenDRA ident ... permit
If permit
is replaced by allow
the ellipsis
is ignored, if warning
is used tchk produces a warning
and if disallow
is used the default behaviour is restored.7.14 Conditional lvalues
The ? operator cannot normally be used to define an lvalue, so that
for example, the program:
struct s {int a, b; };
void f (int n,struct s *s1,struct s *s2) {
( n ? s1: s2)->a = 0;
}
is not allowed in ISO C. The pragma:
#pragma TenDRA conditional lvalue allow
allows conditional lvalues if:
(there is also a disallow
variant, but warning
is not permitted in this case).7.15 Unifying the tag name space
Each object in the tag name space is associated with a classification
(struct, union or enum) of the type to which it refers. If such a
tag is used, it must be preceded by the correct classification, otherwise
the checker produces an error by default. However, the pragma:
#pragma TenDRA ignore struct/union/enum tag status
may be used to change the severity of the error. The options for status
are: on
(allows a tag to be used with any of the
three classifications, the correct classification being inferred from
the type definition), warning
or off
.7.16 Initialisation of compound types
Many older C dialects do not allow the initialisation of automatic
variables of compound type. Thus, for example:
void f () {
struct {
int a;
int b;
} x = { 3, 2 };
}
would not be allowed by some older compilers, although by default
tchk does not raise any errors since the code is legal according to
the ISO C standard. The checker's behaviour may be changed using:
#pragma TenDRA initialization of struct/union (auto) permit
where permit
is allow
, warning
or disallow
. This feature is particularly useful when
developing a program which is intended to be compiled with a compiler
which does not support automatic compound initialisations.7.17 Variable initialisation
The ISO C standard (Section 6.5.7) states that all expressions in
an initialiser for an object that has static storage duration or in
an initialiser-list for an object that has aggregate or union type
shall be constant expressions. The pragma:
#pragma TenDRA variable initialization permit
may be used to allow non-constant initialisers if permit
is replaced by allow
. The other option for permit
is disallow
which restores the default behaviour of flagging
non-constant initialisers for objects of static storage duration as
errors.7.18 Escape sequences
The ISO C standard specifies a small set of escape sequences in strings,
for example \n as newline. Unknown escape sequences lead to an error
in the default mode , however the severity of the error may be altered
using:
#pragma TenDRA unknown escape permit
where permit is allow
(silently replaces the
unknown escape sequence, \z say, by z), warning
or disallow
.7.19 $ in identifier names
The ISO C standard (Section 6.1) states that the use of the character
$ in identifier names is illegal. The pragma:
#pragma TenDRA dollar as ident allow
can be used to allow such identifiers, which by default are flagged
as errors. There is also a disallow
variant which restores
the default behaviour. 7.20 Writeable string literals
The ISO C standard, section 6.1.4, states that "if the program
attempts to modify a string literal of either form, the behaviour
is undefined". Assignments to string literals of the form:
"abc"='3';
always result in errors. Other attempts to modify members of string
literals, e.g.
"abc"[1]='3';
are permitted in the default checking mode. This behaviour can be
changed using:
#pragma TenDRA writeable string literal permit
where permit may be allow
, warning
or disallow
.7.21 Concatenation of character string literals
and wide character string literals
The ISO C standard, section 6.1.4, states that if a character string
literal is adjacent to a wide character string literal, the behaviour
is undefined. By default, this is flagged as an error by the checker.
If the pragma:
#pragma TenDRA unify incompatible string literal permit
is used, with permit set to allow
or warning
the character string literal is converted to a wide character string
literal and the strings are concatenated, although in the warning
case a warning is output. The disallow
version
of the pragma restores the default behaviour.7.22 Nested comments
The occurence of the `/*' characters inside a C comment, i.e. text
surrounded by the `/*' and `*/' symbols, is usually a mistake and
can lead to the termination of a comment unexpectedly. By default
such nested comments are processed silently, however an error or warning
can be produced by setting:
#pragma TenDRA nested comment analysis status
with status as on
or warning
. If
status is off
the default behaviour is restored.7.23
Empty source files
The ISO standard states that each source file should contain at least
one declaration or definition. Source files which contain no external
declarations or definitions are flagged as errors by the checker in
default mode. The severity of the error may be altered using:
#pragma TenDRA no external declaration permit
where the options for permit
are allow
(no
errors raised), warning
or disallow
.7.24 Extra commas
The ISO C standard does not allow extra commas in enumeration type
declarations e.g.
enum e = {red, orange, yellow,};
The extra comma at the end of the declaration is flagged as an error
by default, but this behaviour may be changed by using:
#pragma TenDRA extra , permit
where permit has the usual allow
,
disallow
and warning
options. 7.25 Extra semicolons
Some dialects of C allow extra semicolons at the external declaration
and definition level in contravention of the ISO C standard. For example,
the program:
int f () {
return ( 0 );
};
is not ISO compliant. The checker enforces the ISO rules by default,
but the errors raised may be reduced to warning or suppressed entirely
using:
#pragma TenDRA extra ; permit
with permit as warning
or allow
.
The disallow
option restores the default behaviour.7.26 Compatibility with C++ to TDF producer
In the interests of compatibility between the C checker and the new
C++ checker, all pragmas beginning:
#pragma TenDRA ++
are silently ignored by tchk.
Crown
Copyright © 1998.