Gimpel Software
  Order        Patches        Discussion Forum        Blog 
Contact      Site Map       
   Home
   Bug of the Month
   Products
   Order
   Support
   Company
   Links
   Interactive Demo

Weak Definial Checking

Unused Headers | Removable from Header | Externals that can be made Static

The weak definials consist of the following:

            macro definitions
            typedef's
            declarations
            struct, union and enum definitions and members
            template's

They are compile-time entities and for this reason, perhaps, they are not used as carefully or as scrupulously as run-time objects. Their definitions may be redundant or may lay around unused. Sometimes they are defined inconsistently across modules. Because they are only compile-time entities, they are referred to as 'weak'. The word 'definial' means simply that which is defined. It has the benefit of no prior use and hence semantic neutrality in C or C++. Where there is no possibility of confusion, we will use the word 'definial' as an abbreviation for the term 'weak definial'.

The weak definials are important because they represent those entities normally placed into headers to provide communication for the many modules that comprise a program. To determine whether a header is unused or not depends upon whether any of its weak definials have been used.

Critical to the identification of unused definials is the notion of a library header. By default, headers included via the <filename> syntax and headers included via the assistance of an include directory (identified with a -idirectory option), are considered to be library headers. Other criterion can be added and these criterion can be dropped for the purpose of identifying library headers.

The leading idea of a library header is that the header is employed in more than one program. For this reason, unused weak definials that appear within library headers go unreported. Otherwise, weak definials that appear within project headers (headers that are not library) and within modules are reported upon if they are unused.

Unused Headers

Whether a header is used or not depends on whether any of its definials have been used by any file other than itself or the set of files in the same group. A group of headers is defined below. For now assume a group contains just the file itself. For example, let the complete contents of hdr.h be:

          typedef int INT;
          extern INT f();

Assume a single module includes this header but makes no use of either f or of INT. The definial INT would be considered used by virtue of its appearance within the declaration of f and f would be reported unused. The header would be reported unused by the module because the only use of any of its definials was a self reference, a reference to INT from within the same header. If the declaration of f were removed, then INT would be reported as unused and hdr.h would also be reported as unused.

Consider the following example:

          hdr.h:

                  typedef int INT;


          alpha.c:

                  #include "hdr.h"
                  typedef int INT;
                  INT x = 0;

Is the definial INT within hdr.h being used or not? Is the header hdr.h being used? Since we have two identical declarations for INT it is hard to say. What we do in this case is report that the second typedef is redundant. We then act as if the second never appeared and so the header appears to have been used. If the second typedef were a different type, an error would be reported, and the first typedef would be considered unused.

A group of headers is defined by a #include at the module level and contains the included header and all other headers directly or indirectly included by that header. It is important to note that the base of a group is a header directly included by a module.

Consider an example where module.c includes group.h which, in turn, includes hdr1.h and hdr2.h. If hdr2.h uses something out of hdr1.h this is not considered a module use since both headers lie in the same group (consisting of group.h, hdr1.h and hdr2.h). If module.c makes no other reference to any item in the group you will receive a message (766) header file not used for group.h (i.e. the base of the group.) You will not normally receive a message about the subheaders hdr1.h and hdr2.h not used (this is available as Elective Note 966). Experience has shown that programmers are much more interested in eliminating #include's at the module level. Modifying headers themselves may be unwise owing to the variety of contexts in which headers are used.

In a similar vein, if module.c uses something from, say hdr1.h, but nothing from group.h, group.h is nonetheless considered used and 766 is not issued. You can learn that group.h was not used directly by enabling Elective Note 964 but this fact is not normally very interesting as it would require a rearrangement of header information to exploit.

If module.c includes another header group2.h, then any reference to an element of group.h by this new header, lying as it does in some other group, is considered a reference by the module and serves to suppress 766 for group.h.

Removable from Header

A special message (759) is issued for objects declared in headers but then not referenced outside the module that defines them. (This message is automatically suppressed if there is only one module being processed). If a declaration is used by only one module, it can be removed from the header thereby reducing its size. Headers have a tendency to become big and fat; compilers are always indicating when something has to be added but hardly ever indicate when something can be deleted; this produces uni-directional growth. Message 759 is intended to combat this tendency.

static-able

A related message (765) is the identification of all objects that are 'file-scopable'; i.e., external objects that may be tagged static and hence not placed into the pool of external names. A programmer may not at all be interested in staticizing everything because modern debuggers sometimes depend critically on such external symbols. However you may wish to employ the following technique:

            #if debug && !defined(_lint)
            #define LOCALF
            #define LOCALD extern
            #else
            #define LOCALF static
            #define LOCALD static
            #endif

LOCALD stands for local Declaration.
LOCALF stands for local deFinition.

These are used as:

            LOCALD double func( );
              .
              .
              .
            LOCALF double func( ) {return 37.5; }

For debugging (and provided we are not running PC-lint/FlexeLint) the function func is external and its name is available to the debugger. Otherwise it is made static. The macros provide good documentation and PC-lint/FlexeLint enforces compliance.


Home | Contact | Order

PC-lint and FlexeLint are trademarks of Gimpel Software LLC
Copyright © 2015, Gimpel Software LLC, All rights reserved.