<< Previous | Index | Next >> | |
|
Dynamic C is based on the C language. The programmer is expected to know programming methodologies and the basic principles of the C language. Dynamic C has its own set of libraries, which include user-callable functions. Please see the Dynamic C Function Reference Manual for detailed descriptions of these API functions. Dynamic C libraries are in source code, allowing the creation of customized libraries.
Before starting on your application, read through the rest of this chapter to review C-language features and understand the differences between standard C and Dynamic C.
4.1 C Language Elements
A Dynamic C program is a set of files consisting of one file with a
.c
extension and the requested library files. Each file is a stream of characters that compose statements in the C language. The language has grammar and syntax, that is, rules for making statements. Syntactic elements--often called tokens--form the basic elements of the C language. Some of these elements are listed in the table below.4.2 Punctuation and Tokens
Punctuation marks serve as boundaries in C programs. The table below lists the punctuation marks and tokens.
4.3 Data
Data (variables and constants) have type, size, structure, and storage class. Basic, or primitive, data types are shown below.
4.3.1 Data Type Limits
The symbolic names for the hardcoded limits of the data types are defined in
limits.h
and are shown here.4.4 Names
Names identify variables, certain constants, arrays, structures, unions, functions, and abstract data types. Names must begin with a letter or an underscore (
_
), and thereafter must be letters, digits, or an underscore. Names may not contain any other symbols, especially operators. Names are distinct up to 32 characters, but may be longer. Prior to Dynamic C version 6.19, names were distinct up to 16 characters, but could be longer. Names may not be the same as any keyword. Names are case-sensitive.Examples
my_function // ok
_block // ok
test32 // okjumper- // not ok, uses a minus sign
3270type // not ok, begins with digitCleanup_the_data_now // These names are
Cleanup_the_data_later // not distinct!References to structure and union elements require compound names. The simple names in a compound name are joined with the dot operator (period).
cursor.loc.x = 10; // set structure element to 10
Use the
#define
directive to create names for constants. These can be viewed as symbolic constants. See Section 4.5, "Macros."
#define READ 10
#define WRITE 20
#define ABS 0
#define REL 1
#define READ_ABS READ + ABS
#define READ_REL READ + RELThe term
READ_ABS
is the same as 10 + 0 or 10, andREAD_REL
is the same as 10 + 1 or 11. Note that Dynamic C does not allow anything to be assigned to a constant expression.READ_ABS = 27; // produces compiler error
4.5 Macros
Macros may be defined in Dynamic C by using
#define
. A macro is a name replacement feature. Dynamic C has a text preprocessor that expands macros before the program text is compiled. The programmer assigns a name, up to 31 characters, to a fragment of text. Dynamic C then replaces the macro name with the text fragment wherever the name appears in the program. In this example,
#define OFFSET 12
#define SCALE 72
int i, x;
i = x * SCALE + OFFSET;the variable
i
gets the valuex * 72 + 12
. Macros can have parameters such as in the following example.
#define word( a, b ) (a<<8 | b)
char c;
int i, j;
i = word( j, c ); // same asi = (j<<8|c)
The compiler removes the surrounding white space (comments, tabs and spaces) and collapses each sequence of white space in the macro definition into one space. It places a
\
before any"
or\
to preserve their original meaning within the definition.Dynamic C implements the
#
and##
macro operators.The
#
operator forces the compiler to interpret the parameter immediately following it as a string literal. For example, if a macro is defined#define report(value,fmt)\
printf( #value "=" #fmt "\n", value )report( string, %s );
printf( "string" "=" "%s" "\n", string );
and because C always concatenates adjacent strings, the final result of expansion will be
printf( "string=%s\n", string );
The
##
operator concatenates the preceding character sequence with the following character sequence, deleting any white space in between. For example, given the macro#define set(x,y,z) x ## z ## _ ## y()
set( AASC, FN, 6 );
AASC6_FN();
For parameters immediately adjacent to the
##
operator, the corresponding argument is not expanded before substitution, but appears as it does in the macro call.Generally speaking, Dynamic C expands macro calls recursively until they can expand no more. Another way of stating this is that macro definitions can be nested.
The exceptions to this rule are
Arguments to the
#
and##
operators are not expanded.To prevent infinite recursion, a macro does not expand within its own expansion.
The following complex example illustrates this.
#define A B
#define B C
#define uint unsigned int
#define M(x) M ## x
#define MM(x,y,z) x = y ## z
#define string something
#define write( value, fmt )\
printf( #value "=" #fmt "\n", value )The code
uint z;
M (M) (A,A,B);
write(string, %s);will expand first to
unsigned int z; // simple expansion
MM (A,A,B); //M(M)
does not expand recursively
printf( "string" "=" "%s" "\n", string );
// #value "string" #fmt "%s"then to
unsigned int z;
A = AB; // from A = A ## B
printf( "string" "=" "%s" "\n", something );
// string somethingthen to
unsigned int z;
B = AB; // A B
printf( "string=%s\n", something ); // concatenationand finally to
unsigned int z;
C = AB; // B C
printf("string = %s\n", something);4.5.1 Restrictions
The number of arguments in a macro call must match the number of parameters in the macro definition. An empty parameter list is allowed, but the macro call must have an empty argument list. Macros are restricted to 32 parameters and 126 nested calls. A macro or parameter name must conform to the same requirements as any other C name. The C language does not perform macro replacement inside string literals or character constants, comments, or within a
#define
directive.A macro definition remains in effect unless removed by an
#undef
directive. If an attempt is made to redefine a macro without using#undef
, a warning will appear and the original definition will remain in effect.4.6 Numbers
Numbers are constant values and are formed from digits, possibly a decimal point, and possibly the letters
U, L, X
, orA-F
, or their lower case equivalents. A decimal point or the presence of the letterE
orF
indicates that a number is real (has a floating-point representation).Integers have several forms of representation. The normal decimal form is the most common.
10 -327 1000 0
An integer is long (32-bit) if its magnitude exceeds the 16-bit range (-32768 to +32767) or if it has the letter
L
appended.0L -32L 45000 32767L
An integer is unsigned if it has the letter
U
appended. It islong
if it also hasL
appended or if its magnitude exceeds the 16-bit range.0U 4294967294U 32767U 1700UL
An integer is hexadecimal if preceded by
0x
.0x7E 0xE000 0xFFFFFFFA
It may contain digits and the letters
a-f
orA-F
.An integer is octal if begins with zero and contains only the digits
0-7
.0177 020000 000000630
A real number can be expressed in a variety of ways.
4.5 means 4.5
4f means 4.0
0.3125 means 0.3125
456e-31 means 456 × 10-31
0.3141592e1 means 3.141592
4.7 Strings and Character Data
A string is a group of characters enclosed in double quotes ("").
"Press any key when ready..."
Strings in C have a terminating null byte appended by the compiler. Although C does not have a string data type, it does have character arrays that serve the purpose. C does not have string operators, such as concatenate, but library functions
strcat()
andstrncat()
are available.Strings are multibyte objects, and as such they are always referenced by their starting address, and usually by a
char*
variable. More precisely, arrays are always passed by address. Passing a pointer to a string is the same as passing the string. Refer to Section 4.15 for more information on pointers.The following example illustrates typical use of strings.
const char* select = "Select option\n";
char start[32];
strcpy(start,"Press any key when ready...\n");
printf( select ); // pass pointer to string
...
printf( start ); // pass string4.7.1 String Concatenation
Two or more string literals are concatenated when placed next to each other. For example:
"Rabbits" "like carrots."
"Rabbits like carrots."
If the strings are on multiple lines, the macro continuation character must be used. For example:
"Rabbits"\
"don't like line dancing.""Rabbits don't like line dancing."
4.7.2 Character Constants
Character constants have a slightly different meaning. They are not strings. A character constant is enclosed in single quotes (' ') and is a representation of an 8-bit integer value.
'a' '\n' '\x1B'
Any character can be represented by an alternate form, whether in a character constant or in a string. Thus, nonprinting characters and characters that cannot be typed may be used.
A character can be written using its numeric value preceded by a backslash.
\x41 // the hex value 41
\101 // the octal value 101, a leading zero is optional
\B10000001 // the binary value 10000001There are also several "special" forms preceded by a backslash.
\a bell
\f formfeed
\r carriage return
\v vertical tab
\\ backslash
\' single quote\b backspace
\n newline
\t tab
\0 null character
\c the actual character c
\" double quoteExamples
4.8 Statements
Except for comments, everything in a C program is a statement. Almost all statements end with a semicolon. A C program is treated as a stream of characters where line boundaries are (generally) not meaningful. Any C statement may be written on as many lines as needed. Comments (the
/*...*/
kind) may occur almost anywhere, even in the middle of a statement, as long as they begin with/*
and end with*/
.A statement can be many things. A declaration of variables is a statement. An assignment is a statement. A
while
orfor
loop is a statement. A compound statement is a group of statements enclosed in braces{
and}
.4.9 Declarations
A variable must be declared before it can be used. That means the variable must have a name and a type, and perhaps its storage class could be specified. If an array is declared, its size must be given. Root data arrays are limited to a total of 32,767 elements.
If an aggregate type (
struct
orunion
) is being declared, its internal structure has to be described as shown below.
struct { // description of structure
char flags;
struct { // a nested structure here
int x;
int y;
} loc;
} cursor;
...
int a;
a = cursor.loc.x; // use of structure element here4.10 Functions
The basic unit of a C application program is a function. Most functions accept parameters--or arguments--and return results, but there are exceptions. All C functions have a return type that specifies what kind of result, if any, it returns. A function with a
void
return type returns no result. If a function is declared without specifying a return type, the compiler assumes that it is to return anint
(integer) value.A function may call another function, including itself (a recursive call). The
main
function is called automatically after the program compiles or when the controller powers up. The beginning of themain
function is the entry point to the entire program.4.11 Prototypes
A function may be declared with a prototype. This is so that:
Functions that have not been compiled may be called.
Recursive functions may be written.
The compiler may perform type-checking on the parameters to make sure that calls to the function receive arguments of the expected type.
A function prototype describes how to call the function and is nearly identical to the function's initial code.
/* This is a function prototype.*/
long tick_count ( char clock_id );/* This is the function's definition.*/
long tick_count ( char clock_id ){
...
}It is not necessary to provide parameter names in a prototype, but the parameter type is required, and all parameters must be included. (If the function accepts a variable number of arguments, as
printf
does , use an ellipsis.)
/* This prototype is as good as the one above. */
long tick_count ( char );/* This is a prototype that uses ellipsis. */
int startup ( device id, ... );4.12 Type Definitions
Both types and variables may be defined. One virtue of high-level languages such as C and Pascal is that abstract data types can be defined. Once defined, the data types can be used as easily as simple data types like
int
,char
, andfloat
. Consider this example.Use
typedef
to create a meaningful name for a class of data. Consider this example.
typedef unsigned int node;
void NodeInit( node ); // type name is informative
void NodeInit( unsigned int ); // not very informativeThis example shows many of the basic C constructs.
The program above calculates the sum of squares of two numbers,
g
andh
, which are initialized to 10 and 12, respectively. The main function calls theinit
function to give values to the global variablesg
andh
. Then it uses thesumSquare
function to perform the calculation and assign the result of the calculation to the variablex
. It prints the result using the library functionprintf
, which includes a formatting string as the first argument.Notice that all functions have
{
and}
enclosing their contents, and all variables are declared before use. The functionsinit()
andsumSquare()
were defined before use, but there are alternatives to this. The "Prototypes" section explained this.4.13 Aggregate Data Types
Simple data types can be grouped into more complex aggregate forms.
4.13.1 Array
A data type, whether it is simple or complex, can be replicated in an array. The declaration
int item[10]; // An array of 10 integers.
represents a contiguous group of 10 integers. Array elements are referenced by their subscript.
j = item[n]; // The nth element of item.
Array subscripts count up from 0. Thus,
item[7]
above is the eighth item in the array. Notice the[
and]
enclosing both array dimensions and array subscripts. Arrays can be "nested." The following doubly dimensioned array, or "array of arrays."
int matrix[7][3];
is referenced in a similar way.
scale = matrix[i][j];
The first dimension of an array does not have to be specified as long as an initialization list is specified.
int x[][2] = { {1, 2}, {3, 4}, {5, 6} };
char string[] = "abcdefg";4.13.2 Structure
Variables may be grouped together in structures (
struct
in C) or in arrays. Structures may be nested.
struct {
char flags;
struct {
int x;
int y;
} loc;
} cursor;Structures can be nested. Structure members--the variables within a structure--are referenced using the dot operator.
j = cursor.loc.x
The size of a structure is the sum of the sizes of its components.
4.13.3 Union
A union overlays simple or complex data. That is, all the union members have the same address. The size of the union is the size of the largest member.
union {
int ival;
long jval;
float xval;
} u;Unions can be nested. Union members--the variables within a union--are referenced, like structure elements, using the dot operator.
j = u.ival
4.13.4 Composites
Composites of structures, arrays, unions, and primitive data may be formed. This example shows an array of structures that have arrays as structure elements.
typedef struct {
int *x;
int c[32]; // array in structure
} node;node list[12]; // array of structures
Refer to an element of array
c
(above) as shown here.
z = list[n].c[m];
...
list[0].c[22] = 0xFF37;4.14 Storage Classes
Variable storage can be
auto
orstatic
. The default storage class isstatic
, but can be changed by using#class auto
. The default storage class can be superseded by the use of the keywordauto
orstatic
in a variable declaration.These terms apply to local variables, that is, variables defined within a function. If a variable does not belong to a function, it is called a global variable--available anywhere in the program--but there is no keyword in C to represent this fact. Global variables always have
static
storageThe term
static
means the data occupies a permanent fixed location for the life of the program. The termauto
refers to variables that are placed on the system stack for the life of a function call.4.15 Pointers
A pointer is a variable that holds the 16-bit logical address of another variable, a structure, or a function. Dynamic C does not currently support long pointers. The indirection operator (*) is used to declare a variable as a pointer. The address operator (&) is used to set the pointer to the address of a variable.
int *ptr_to_i;
int i;
ptr_to_i = &i; // set pointer equal to the address of i
i = 10: // assign a value to i
j = *ptr_to_i; // this sets j equal to the value in iIn this example, the variable
ptr_to_i
is a pointer to an integer. The statementj =
*ptr_to_i
; references the value of the integer by the use of the asterisk. Using correct pointer terminology, the statement dereferences the pointerptr_to_i
. Then*ptr_to_i
andi
have identical values.Note that
ptr_to_i
andi
do not have the same values becauseptr_to_i
is a pointer andi
is anint
. Note also that*
has two meanings (not counting its use as a multiplier in others contexts) in a variable declaration such asint *ptr_to_i;
the*
means that the variable will be a pointer type, and in an executable statementj = *ptr_to_i;
means "the value stored at the address contained inptr_to_i
."Pointers may point to other pointers.
It is possible to do pointer arithmetic, but this is slightly different from ordinary integer arithmetic. Here are some examples.
float f[10], *p, *q; // an array and some ptrs
p = &f; // point p to array element 0
q = p+5; // point q to array element 5
q++; // point q to array element 6
p = p + q; // illegal!Because the
float
is a 4-byte storage element, the statementq = p+5
sets the actual value ofq
top+20.
The statementq++
adds 4 to the actual value ofq
. Iff
were an array of 1-byte characters, the statementq++
adds 1 toq
.Beware of using uninitialized pointers. Uninitialized pointers can reference ANY location in memory. Storing data using an uninitialized pointer can overwrite code or cause a crash.
A common mistake is to declare and use a pointer to
char
, thinking there is a string. But an uninitialized pointer is all there is.
char* string;
...
strcpy( string, "hello" ); // Invalid!
printf( string ); // Invalid!Pointer checking is a run-time option in Dynamic C. Use the compiler options command in the Options menu. Pointer checking will catch attempts to dereference a pointer to un allocated memory. However, if an uninitialized pointer happens to contain the address of a memory location that the compiler has already allocated, pointer checking will not catch this logic error. Because pointer checking is a run-time option, pointer checking adds instructions to code when pointer checking is used.
4.16 Pointers to Functions, Indirect Calls
Pointers to functions may be declared. When a function is called using a pointer to it, instead of directly, we call this an indirect call.
The syntax for declaring a pointer to a function is different than for ordinary pointers, and Dynamic C syntax for this is slightly different than the standard C syntax. Standard syntax for a pointer to a function is:
returntype (*name)( [argument list] );
for example:
int (*func1)(int a, int b);
void (*func2)(char*);Dynamic C doesn't recognize the argument list in function pointer declarations. The correct Dynamic syntax for the above examples would be:
int (*func1)();
void (*func2)();You can pass arguments to functions that are called indirectly by pointers, but the compiler will not check them for correctness. The following program shows some examples of using function pointers.
4.17 Argument Passing
In C, function arguments are generally passed by value. That is, arguments passed to a C function are generally copies--on the program stack--of the variables or expressions specified by the caller. Changes made to these copies do not affect the original values in the calling program.
In Dynamic C and most other C compilers, however, arrays are always passed by address. This policy includes strings (which are character arrays).
Dynamic C passes
structs
by value--on the stack. Passing a largestruct
takes a long time and can easily cause a program to run out of memory. Pass pointers to largestructs
if such problems occur.For a function to modify the original value of a parameter, pass the address of, or a pointer to, the parameter and then design the function to accept the address of the item.
4.18 Program Flow
Three terms describe the flow of execution of a C program: sequencing, branching and looping. Sequencing is simply the execution of one statement after another. Looping is the repetition of a group of statements. Branching is the choice of groups of statements. Program flow is altered by calling a function, that is transferring control to the function. Control is passed back to the calling function when the called function returns.
4.18.1 Loops
A
while
loop tests a condition at the start of the loop. As long as expression is true (non-zero), the loop body (some statement(s)) will execute. If expression is initially false (zero), the loop body will not execute. The curly braces are necessary if there is more than one statement in the loop body.
while( expression ){
some statement(s)
}A
do
loop tests a condition at the end of the loop. As long as expression is true (non-zero) the loop body (some statement(s)) will execute. Ado
loop executes at least once before its test. Unlike other controls, thedo
loop requires a semicolon at the end.
do{
some statements
}while( expression );The
for
loop is more complex: it sets an initial condition (exp1), evaluates a terminating condition (exp2), and provides a stepping expression (exp3) that is evaluated at the end of each iteration. Each of the three expressions is optional.
for( exp1 ; exp2 ; exp3 ){
some statements
}If the end condition is initially false, a
for
loop body will not execute at all. A typical use of thefor
loop is to countn
times.
sum = 0;
for( i = 0; i < n; i++ ){
sum = sum + array[i];
}This loop initially sets
i
to 0, continues as long asi
is less thann
(stops wheni
equalsn
), and incrementsi
at each pass.Another use for the
for
loop is the infinite loop, which is useful in control systems.
for(;;){some statement(s)}
Here, there is no initial condition, no end condition, and no stepping expression. The loop body (some statement(s)) continues to execute endlessly. An endless loop can also be achieved with a
while
loop. This method is slightly less efficient than thefor
loop.
while(1) { some statement(s) }
4.18.2 Continue and Break
Two keywords are available to help in the construction of loops:
continue
andbreak
.The
continue
statement causes the program control to skip unconditionally to the next pass of the loop. In the example below, ifbad
is true, more statements will not execute; control will pass back to the top of thewhile
loop.
get_char();
while( ! EOF ){
some statements
if( bad ) continue;
more statements}
The
break
statement causes the program control to jump unconditionally out of a loop. In the example below, ifcond_RED
is true, more statements will not be executed and control will pass to the next statement after the ending curly brace of thefor
loop
for( i=0;i<n;i++ ){
some statements
if( cond_RED ) break;
more statements}
The
break
keyword also applies to theswitch/case
statement described in the next section. Thebreak
statement jumps out of the innermost control structure (loop or switch statement) only.There will be times when
break
is insufficient. The program will need to either jump out more than one level of nesting or there will be a choice of destinations when jumping out. Use agoto
statement in such cases. For example,
while( some statements ){
for( i=0;i<n;i++ ){
some statements
if( cond_RED ) goto yyy;
some statements
if( code_BLUE ) goto zzz;
more statements
}
}
yyy:
handle cond_RED
zzz:
handle code_BLUE4.18.3 Branching
The
goto
statement is the simplest form of a branching statement. Coupled with a statement label, it simply transfers program control to the labeled statement.
some statements
abc:
other statements
goto abc;
...
more statements
goto def;
...
def:
more statementsThe colon at the end of the labels is required. In general, the use of the
goto
statement is discouraged in structured programming.The next simplest form of branching is the
if
statement. The simple form of theif
statement tests a condition and executes a statement or compound statement if the condition expression is true (non-zero). The program will ignore theif
body when the condition is false (zero).
if( expression ){
some statement(s)
}A more complex form of the
if
statement tests the condition and executes certain statements if the expression is true, and executes another group of statements when the expression is false.
if( expression ){
some statement(s) // if true
}else{
some statement(s) // if false
}The fullest form of the
if
statements produces a succession of tests.
if( expr1 ){
some statements
}else if( expr2 ){
some statements
}else if( expr3 ){
some statements
...
}else{
some statements
}The program evaluates the first expression (expr1). If that proves false, it tries the second expression (expr2), and continues testing until it finds a true expression, an
else
clause, or the end of the if statement. Anelse
clause is optional. Without anelse
clause, anif/else if
statement that finds no true condition will execute none of the controlled statements.The
switch
statement, the most complex branching state-ment, allows the programmer to phrase a "multiple choice" branch differently.
switch( expression ){
case
const
1 :
statements1
break:case
const
2 :
statements2
break:case
const
3 :
statements3
break:...
default:
statementsDEFAULT
}First the
switch
expression is evaluated. It must have an integer value. If one of theconst
N values matches theswitch
expression, the sequence of statements identified by theconst
N expression is executed. If there is no match, the sequence of statements identified by thedefault
label is executed. (Thedefault
part is optional.) Unless thebreak
keyword is included at the end of the case's statements, the program will "fall through" and execute the statements for any number of other cases. Thebreak
keyword causes the program to exit theswitch/case
statement.The colons (
:
) afterbreak
,case
anddefault
are required.4.19 Function Chaining
Function chaining allows special segments of code to be distributed in one or more functions. When a named function chain executes, all the segments belonging to that chain execute. Function chains allow the software to perform initialization, data recovery, and other kinds of tasks on request. There are two directives,
#makechain
and#funcchain
, and one keyword,segchain
that create and control function chains:#makechain chain_name
- Creates a function chain. When a program executes the named function chain, all of the functions or chain segments belonging to that chain execute. (No particular order of execution can be guaranteed.)
#funcchain chain_name name
- Adds a function, or another function chain, to a function chain.
segchain
chain_name { statements }
- Defines a program segment (enclosed in curly braces) and attaches it to the named function chain.
Function chain segments defined with
segchain
must appear in a function directly after data declarations and before executable statements, as shown below.A program will call a function chain as it would an ordinary void function that has no parameters. The following example shows how to call a function chain that is named
recover
.
#makechain recover
...recover();
4.20 Global Initialization
Various hardware devices in a system need to be initialized not only by setting variables and control registers, but often by complex initialization procedures. Dynamic C provides a specific function chain,
_GLOBAL_INIT
, for this purpose.Your program can initialize variables and take initialization action with global initialization. This is done by adding segments to the
_GLOBAL_INIT
function chain, as shown in the example below.The special directive
#GLOBAL_INIT{ }
tells the compiler to add the code in the block enclosed in braces to the_GLOBAL_INIT
function chain. The_GLOBAL_INIT
function chain is always called when your program starts up, so there is nothing special to do to invoke it. It may be called at anytime in an application program, but do this with caution. When it is called, all costatements and cofunctions will be initialized. See Calling _GLOBAL_INIT() for more information.Any number of
#GLOBAL_INIT
sections may be used in your code. The order in which the#GLOBAL_INIT
sections are called is indeterminate since it depends on the order in which they were compiled.4.21 Libraries
Dynamic C includes many libraries--files of useful functions in source code form. They are located in the
LIB
subdirectory where Dynamic C was installed. The default library file extension is.LIB
. Dynamic C uses functions and data from library files and compiles them with an application program that is then downloaded to a controller or saved to a.bin
file.An application program (the default file extension is
.c
) consists of a source code file that contains a main function (calledmain
) and usually other user-defined functions. Any additional source files are considered to be libraries (though they may have a.c
extension if desired) and are treated as such. The minimum application program is one source file, containing onlymain(){
}Libraries (both user defined and Z-World defined) are "linked" with the application through the
#use
directive. The#use
directive identifies a file from which functions and data may be extracted. Files identified by#use
directives are nestable, as shown below. The#use
directive is a replacement for the#include
directive, which is not supported in Dynamic C. Any library that is to be used in a Dynamic C program must be listed in the fileLIB.DIR
, or another*.DIR
file specified by the user. (Starting with version Dynamic C 7.05, a different*.DIR
file may be specified by the user in the Compiler Options dialog to facilitate working on multiple projects.)Most libraries needed by Dynamic C programs are
#use
'd in the filelib\default.h
.The "Modules" section later in this chapter explains how Dynamic C knows which functions and global variables in a library to use.
4.22 Headers
The following table describes two kinds of headers used in Dynamic C libraries.
You may also notice some "Library Description" headers at the top of library files. These have no special meaning to Dynamic C, they are simply comment blocks.
4.23 Modules
To write a custom source library, modules must be understood because they provide Dynamic C with the ability to know which functions and global variables in a library to use. It is important to note that the
#use
directive is a replacement for the#include
directive, and the#include
directive is not supported.A library file contains a group of modules. A module has three parts: the key, the header, and a body of code (functions and data).
A module in a library has a structure like this one.
/*** BeginHeader func1, var2, .... */
prototype for func1
declaration for var2
/*** EndHeader */
definition of func1 and
possibly other functions and data4.23.1 The Key
The line (a specially-formatted comment)
/*** BeginHeader [name1, name2, ....] */
begins the header of a module and contains the module key. The key is a list of names (of functions and data). The key tells the compiler what functions and data in the module are available for reference. It is important to format this comment properly. Otherwise, Dynamic C cannot identify the module correctly.
If there are many names after
BeginHeader
, the list of names can continue on subsequent lines. All names must be separated by commas. A key can have no names in it and it's associated header will still be parsed by the precompiler and compiler.4.23.2 The Header
Every line between the comments containing
BeginHeader
andEndHeader
belongs to the header of the module. When an application#use
s a library, Dynamic C compiles every header, and just the headers, in the library. The purpose of a header is to make certain names defined in a module known to the application. With proper function prototypes and variable declarations, a module header ensures proper type checking throughout the application program. Prototypes, variables, structures, typedefs and macros declared in a header section will always be parsed by the compiler if the library is used, and will have global scope. It is even permissible to put function bodies in header sections, but this is not recommended. Variables declared in a header section will be allocated memory space unless the declaration is preceded withextern
.4.23.3 The Body
Every line of code after the
EndHeader
comment belongs to the body of the module until (1) end-of-file or (2) theBeginHeader
comment of another module. Dynamic C compiles the entire body of a module if any of the names in the key are referenced (used) anywhere in the application. For this reason, it is not wise to put many functions in one module regardless of whether they are actually going to be used by the program.To minimize waste, it is recommended that a module header contain only prototypes and
extern
declarations. (Prototypes andextern
declarations do not generate any code by themselves.) Define code and data only in the body of a module. That way, the compiler will generate code or allocate data only if the module is used by the application program. Programmers who create their own libraries must write modules following the guideline in this section. Remember that the library must be included inLIB.DIR
(or a user defined replacement forLIB.DIR
) and a#use
directive for the library must be placed somewhere in the code.It should be noted that there is no way to define file scope variables other than having a file consist of a single module (which would mean that all data and functions in the file would be compiled whenever a function specified in the header is compiled).
Example
There are three modules defined in this code. The first one is responsible for the variable
ticks
, the second and third modules define functionsGet_Ticks()
andInc_Ticks
that access the variable. AlthoughInc_Ticks
is an assembly language routine, it has a function prototype in the module header, allowing the compiler to check calls to it.If the application program calls
Inc_Ticks
orGet_Ticks()
(or both), the module bodies corresponding to the called routines will be compiled. The compilation of these routines further triggers compilation of the module body corresponding toticks
because the functions use the variableticks
.4.23.4 Function Description Headers
Each user-callable function in a Z-World library has a descriptive header preceding the function to describe the function. Function headers are extracted by Dynamic C to provide on-line help messages.
The header is a specially formatted comment, such as the following example.
If this format is followed, user-created library functions will show up in the Function Lookup/Insert facility. Note that these sections are scanned in only when Dynamic C starts.
4.24 Support Files
Dynamic C has several support files that are necessary in building an application. These files are listed below.
Table 4-5. Dynamic C Support Files DCW.CFG
Contains configuration data for the target controller. DC.HH
Contains prototypes, basic type definitions, #define
, and default modes for Dynamic C. This file can be modified by the programmer.DEFAULT.H
Contains a set of #use
directives for each control product that Z-World ships. This file can be modified.LIB.DIR
Contains pathnames for all libraries that are to be known to Dynamic C. The programmer can add to, or remove libraries from this list. The factory default is for this file to contain all the libraries on the Dynamic C distribution disk. Any library that is to be used in a Dynamic C program must be listed in the file
LIB.DIR
, or another*.DIR
file specified by the user. (Starting with version Dynamic C 7.05, a different*.DIR
file may be specified by the user in the Compiler Options dialog to facilitate working on multiple projects.)PROJECT.DCP
DEFAULT.DCPThese files hold the default compilation environment that is shipped from the factory.
DEFAULT.DCP
may be modified, but notPROJECT.DCP
. See Chapter 16 for details on project files.
| |
<< Previous | Index | Next >> | |
Z-World, Inc. www.zworld.com Phone: 1.530.757.3737 Fax: 1.530.757.3792 |
Rabbit Semiconductor www.rabbitsemiconductor.com Phone: 1.530.757.8400 Fax: 1.530.757.8402 |