C Checker Reference Manual

January 1998

next section previous section current document TenDRA home page document index


7.1 - Introduction
7.2 - Resolving linkage problems
7.3 - Identifier linkage
7.4 - Implicit integer types
7.5 - Bitfield types
7.6 - Extra type definitions
7.7 - Static block level functions
7.8 - Incomplete array element types
7.9 - Forward enumeration declarations
7.10 - Untagged compound types
7.11 - External volatility
7.12 - Identifier name length
7.13 - Ellipsis in function calls
7.14 - Conditional lvalues
7.15 - Unifying the tag name space
7.16 - Initialisation of compound types
7.17 - Variable initialisation
7.18 - Escape sequences
7.19 - $ in identifier names
7.20 - Writeable string literals
7.21 - Concatenation of character string literals and wide character string literals
7.22 - Nested comments
7.23 - Empty source files
7.24 - Extra commas
7.25 - Extra semicolons
7.26 - Compatibility with C++ to TDF producer

7 Dialect Features


7.1 Introduction

This chapter describes the capabilities of the TenDRA C checker for enforcing the ISO C standard as well as features for detecting areas left undefined by the standard. It also lists the non-ISO dialect features supported by the checker in order to provide compatibility with older versions of C and allow the use of third-party source which may contain non-standard constructs.


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.

Another linkage problem, which is left undefined in the ISO C standard, is illustrated by the following program:

	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:

  1. (internal) on

  2. (internal) warning

  3. (external) on

  4. (external) warning

  5. off

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.


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.

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:

	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).

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:

	#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:

  1. Both options of the conditional operator have compatible compound types;

  2. Both options of the conditional are lvalues.

(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.


Part of the TenDRA Web.
Crown Copyright © 1998.