11. Configuration for linkage

  1. 11.1. Default linkage
  2. 11.2. Identifier linkage
  3. 11.3. Static identifiers
  4. 11.4. External volatility
  5. 11.5. Function linkage
  6. 11.6. Resolving linkage problems

11.1. Default linkage

It is possible to set the default language linkage using the directive:

#pragma TenDRA++ external linkage string-literal

This is equivalent to enclosing the rest of the current checking scope in:

extern string-literal {
	....
}

It is unspecified what happens if such a directive is used within an explicit linkage specification and does not nest correctly. This directive is particularly useful when used in a named environment associated with an include directory. For example, it can be used to express the fact that all the objects declared in headers included from that directory have C linkage.

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

If an object is declared with both external and internal linkage in the same translation unit then, by default, an error is given. This behaviour can be changed using the directive:

#pragma TenDRA incompatible linkage allow

When incompatible linkages are allowed, whether the resultant identifier has external or internal linkage can be set using one of the directives:

#pragma TenDRA linkage resolution : off
#pragma TenDRA linkage resolution : (external) on
#pragma TenDRA linkage resolution : (internal) on

It is possible to declare objects with external linkage in a block. C leaves it undefined whether declarations of the same object in different blocks, such as:

void f ()
{
	extern int a ;
	....
}

void g ()
{
	extern double a ;
	....
}

are checked for compatibility. However in C++ the one definition rule implies that such declarations are indeed checked for compatibility. The status of this check can be set using the directive:

#pragma TenDRA unify external linkage on

11.3. Static identifiers

By default, objects and functions with internal linkage are mapped to tags without external names in the output TDF capsule. Thus such names are not available to the installer and it needs to make up internal names to represent such objects in its output. This is not desirable in such operations as profiling, where a meaningful internal name is needed to make sense of the output. The directive:

#pragma TenDRA preserve identifier-list

can be used to preserve the names of the given list of identifiers with internal linkage. This is done using the static_name_def TDF construct. The form:

#pragma TenDRA preserve *

will preserve the names of all identifiers with internal linkage in this way.

11.4. External volatility

Older dialects of C treated all identifiers with external linkage as if they had been declared volatile (i.e. by being conservative in optimising such values). This behaviour can be enabled using the directive:

#pragma TenDRA external volatile_t
#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.

11.5. Function linkage

A change in ISO C++ relative to older dialects is that the language linkage of a function now forms part of the function type. For example:

extern "C" int f ( int ) ;
int ( *pf ) ( int ) = f ;		// error

The directive:

#pragma TenDRA++ external function linkage on

can be used to control whether function types with differing language linkages, but which are otherwise compatible, are considered compatible or not.

Note that it is not possible in ISO C or C++ to declare objects or functions with internal linkage in a block. While static object definitions in a block have a specific meaning, there is no real reason why static functions should not be declared in a block. This behaviour can be enabled using the directive:

#pragma TenDRA block function static allow

Inline functions have external linkage by default in ISO C++, but internal linkage in older dialects. The default linkage can be set using the directive:

#pragma TenDRA++ inline linkage linkage-spec

where linkage-spec can be external or internal. Similarly const objects have internal linkage by default in C++, but external linkage in C. The default linkage can be set using the directive:

#pragma TenDRA++ const linkage linkage-spec

11.6. 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:

  • (internal) on

  • (internal) warning

  • (external) on

  • (external) warning

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