HP 3000 Manuals

Identifiers [ HP C/iX Reference Manual ] MPE/iX 5.0 Documentation


HP C/iX Reference Manual

Identifiers 

An identifier is a sequence of characters that represents an entity such
as a function or a data object.

Syntax 

     identifier ::= nondigit 
                 identifier nondigit 
                 identifier digit 

     nondigit ::= any character from the set:
                 _ a b c d e f g h i j k l m n o p
                 q r s t u v w x y z A B C D E F G
                 H I J K L M N O P Q R S T U V W X
                 Y Z

     digit ::= any character from the set:
              0 1 2 3 4 5 6 7 8 9
     [REV BEG]
     dollar-sign ::= the $ character[REV END]

Description 

Identifiers must start with a nonnumeric character followed by a sequence
of digits or nonnumeric characters.  Internal and external names may have
up to 255 significant characters.

Identifiers are case sensitive.  The compiler considers uppercase and
lowercase characters to be different.  For example, the identifier CAT is
different from the identifier cat.  This is true for external as well as
internal names.
[REV BEG]

An HP extension to the language non-ANSI mode allows $ as a valid
character in an identifier as long as it is not the first character.[REV
END]

The following are examples of legal
and illegal identifiers:

Legal 

     Sub_Total
     X
     aBc
     Else
     do_123

Illegal 

     3xyz    First character is a digit 
     const   Conflict with a reserved word 
     #note   First character not alphabetic or _ 
     Num'2   Contains an illegal character 

All identifiers that begin with the underscore (_) character are reserved
for system use.  If you define identifiers that begin with an underscore,
the compiler may interpret them as internal system names.  The resulting
behavior is undefined.

Finally, identifiers cannot have the same spelling as reserved words.
For example, int cannot be used as an identifier because it is a reserved
word.  INT is a valid identifier because it has different case letters.

Identifier Scope 

The scope of an identifier is the region of the program in which the
identifier has meaning.  There are four kinds of scope:

   1.  File Scope--Identifiers declared outside of any block or list of
       parameters have scope from their declaration point until the end
       of the translation unit.

   2.  Function Prototype Scope--If the identifier is part of the
       parameter list in a function declaration, then it is visible only
       inside the function declarator.  This scope ends with the function
       prototype.

   3.  Block Scope--Identifiers declared inside a block or in the list of
       parameter declarations in a function definition have scope from
       their declaration point until the end of the associated block.

   4.  Function Scope--Statement labels have scope over the entire
       function in which they are defined.  Labels cannot be referenced
       outside of the function in which they are defined.  Labels do not
       follow the block scope rules.  In particular, goto statements can
       reference labels that are defined inside iteration statements.
       Label names must be unique within a function.

A preprocessor macro is visible from the #define directive that declares
it until either the end of the translation unit or an #undef directive
that undefines the macro.

Identifier Linkage 

An identifier is bound to a physical object by the context of its use.
The same identifier can be bound to several different objects at
different places in the same program.  This apparent ambiguity is
resolved through the use of scope and name spaces.  The term name spaces 
refers to various categories of identifiers in C (see "Name Spaces" later
in this chapter for more information).

Similarly, an identifier declared in different scopes or in the same
scope more than once can be made to refer to the same object or function
by a process called linkage.  There are three kinds of linkage:

   1.  Internal--Within a single translation unit, each instance of an
       identifier with internal linkage denotes the same object or
       function.

   2.  External--Within all the translation units and libraries that
       constitute an entire program, each instance of a particular
       identifier with external linkage denotes the same object or
       function.

   3.  None--Identifiers with no linkage denote unique entities.

If an identifier is declared at file scope using the storage-class
specifier static, it has internal linkage.

If an identifier is declared using the storage-class specifier extern, it
has the same linkage as any visible declaration of the identifier with
file scope.  If there is no visible declaration with file scope, the
identifier has external linkage.

If the declaration of an identifier for a function has no storage-class
specifier, its linkage is determined exactly as if it were declared with
the storage-class specifier extern.  If the declaration of an identifier
for an object has file scope and no storage-class specifier, its linkage
is external.

The following identifiers have no linkage:

   *   An identifier declared to be anything other than an object or a
       function.

   *   An identifier declared to be a function parameter.

   *   A block scope identifier for an object declared without the
       storage-class specifier extern.

For example:

             extern int i;           /* External linkage */
             static float f;         /* Internal linkage */
             struct Q { int z; };    /* Q and z both have no linkage */

             static int func()       /* Internal linkage */
             {
                extern int temp;     /* External linkage */
                static char c;       /* No linkage */
                int j;               /* No linkage */
                extern float f;      /* Internal linkage; refers to */
                                     /* float f at file scope */
              }

Two identifiers that have the same scope and share the same name space
cannot be spelled the same way.  Two identifiers that are not in the same
scope or same name space can have the same spelling and will bind to two
different physical objects.  For example, a formal parameter to a
function may have the same name as a structure tag in the same function.
This is because the two identifiers are not in the same name space.

If one identifier is defined in a block and another is defined in a
nested (subordinate) block, both can have the same spelling.

For
example:

          {
             int i;       <---A 
               .
               .          <---B 
               .
             {
                float i;  <---C 
                   .      <---D 
                   .
                   .
             }            <---E 
             .
             .            <---F 
             .
          }               <---G 

In the example above, the identifier i is bound to two physically
different objects.  One object is an integer and the other is a
floating-point number.  Both objects, in this case, have block scope.  At
location A, identifier i is declared.  Its scope continues until the end
of the block in which it is defined (point G). References to i at
location B refer to an integer object.

At point C, another identifier is declared.  The previous declaration for
i is hidden by the new declaration until the end of the block in which
the new i is declared.  References to the identifier i result in
references to a floating-point number (point D). At the end of the second
block (point E), the floating-point declaration of i ends.  The previous
declaration of i again becomes visible, and references to identifier i at
point F reference an int.

Storage Duration 

Identifiers that represent variables have a real existence at runtime,
unlike identifiers that represent abstractions like typedef names or
structure tags.  The duration of an object's existence is the period of
time in which the object has storage allocated for it.  There are two
different durations for C objects:

   1.  Static--An object whose identifier is declared with external or
       internal linkage, or with the storage-class specifier static, has
       static storage duration.  Objects with static storage duration
       have storage allocated to them when the program begins execution.
       The storage remains allocated until the program terminates.

   2.  Automatic--An object whose identifier is declared with no linkage,
       and without the storage-class specifier static, has automatic
       storage duration.  Objects with automatic storage duration are
       allocated when entering a function and deallocated on exit from a
       function.  If you do not explicitly initialize such an object, its
       contents when allocated will be indeterminate.  Further, if a
       block that declares an initialized automatic duration object is
       not entered through the top of the block, the object will not be
       initialized.

Name Spaces 

In any given scope, you can use an identifier for only one purpose.  An
exception to this rule is caused by separate name spaces.  Different name
spaces allow the same identifier to be overloaded within the same scope.
This is to say that, in some cases, the compiler can determine from the
context of use which identifier is being referred to.  For example, an
identifier can be both a variable name and a structure tag.

Four different name spaces are used in C: 

   1.  Labels--The definition of a label is always followed by a colon (
       :  ).  A label is only referenced as the object of a goto 
       statement.  Labels, therefore, can have the same spelling as any
       nonlabel identifier.

   2.  Tags--Tags are part of structure, union, and enumeration
       declarations.  All tags for these constructs share the same name
       space (even though a preceding struct, union or enum keyword could
       clarify their use).  Tags can have the same spelling as any
       non-tag identifier.

   3.  Members--Each structure or union has its own name space for
       members.  Two different structures can have members with exactly
       the same names.  Members are therefore tightly bound to their
       defining structure.  For example, a pointer to structure of type A
       cannot reference members from a structure of type B. (You may use
       unions or a cast to accomplish this.)

   4.  Other names--All other names are in the same name space, including
       variables, functions, typedef names, and enumeration constants.

Conceptually, the macro prepass occurs before the compilation of the
translation unit.  As a result, macro names are independent from all
other names.  Use of macro names as ordinary identifiers can cause
unwanted substitutions.

Types 

The type of an identifier defines how the identifier can be used.  The
type defines a set of values and operations that can be performed on
these values.  There are three major category of types in C--object type,
function type, and incomplete type.

   I.  Object Type 

       There are 3 object types--scalar, aggregate, and union.  These are
       further subdivided (see figure 2-1).

          1.  Scalar--These types are all objects that the computer can
              directly manipulate.  Scalar types include pointers,
              numeric objects, and enumeration types.

                 a.  Pointer--These types include pointers to objects and
                     functions.

                 b.  Arithmetic--These types include floating and
                     integral types.

                        A.  Floating:  The floating types include the
                            following:

                            Float--A 32-bit floating point number.
                            Double--A 64-bit double precision floating
                            point number.
                            Long double--A 128-bit quad precision
                            floating point number.

                        B.  Integral:  The integral types include all of
                            the integer types that the computer supports.
                            This includes type char, signed and unsigned
                            integer types, and the enumerated types.

                            Char--An object of char type is one that is
                            large enough to store an ASCII character.
                            Internally, a char is a signed integer.

                            Integer--Integers can be short or long; they
                            are normally signed, but can be made unsigned
                            by using the keyword unsigned with the type.
                            In C, a computation involving unsigned
                            operands can never overflow; high-order bits
                            that do not fit in the result field are
                            simply discarded without warning.  A short
                            int is a 16-bit integer.  A long int (or int)
                            is a 32-bit integer.  Integer types include
                            signed char and unsigned char (but not
                            "plain" char).

                            Enumerated--Enumerated types are explicitly
                            listed by the programmer; they name specified
                            integer constant values.  The enumerated type
                            color might, for example, define red, blue,
                            and green.  An object of type enum color
                            could then have the value red, blue, or
                            green.

          2.  Aggregate--Aggregate types are types that are composed of
              other types.  With some restrictions, aggregate types can
              be composed of members of all of the other types including
              (recursively) aggregate types.  Aggregate types include:

                 a.  Structures--Structures are collections of
                     heterogeneous objects.  They are similar to Pascal
                     records and are useful for defining special-purpose
                     data types.

                 b.  Arrays--Arrays are collections of homogeneous
                     objects.  C arrays can be multidimensional with
                     conceptually no limit on the number of dimensions.

          3.  Unions--Unions, like structures, can hold different types
              of objects.  However, all members of a union are
              "overlaid"; that is, they begin at the same location in
              memory.  This means that the union can contain only one of
              the objects at any given time.  Unions are useful for
              manipulating a variety of data within the same memory
              location.

  II.  Function Type 

       A function type specifies the type of the object that a function
       returns.  A function that returns an object of type T can be
       referred to as a "function returning T," or simply, a T function.

 III.  Incomplete Type 

       The void type is an incomplete type.  It comprises an empty set of
       values.  Only pointers and functions can have void type.  A
       function that returns void is a function that returns nothing.  A
       pointer to void establishes a generic pointer.

Figure 2-1 illustrates the C types.

[]
Figure 2-1. C Types


MPE/iX 5.0 Documentation