Prerequisites: Completion of Parts 1 & 2 in previous issues (including the exercises).
Environment: This course addresses the use of "C" in the
ISO-C TPF environment.
In our last installment, we discussed how "C" defines and handles data and structures -- the basic "C" building block for data. In this issue, we'll conclude this course by taking a look at "C" control statements and functions that "C" provides which serve as equivalents to some familiar Assembler instructions.
THE "if" CONTROL STATEMENT
Sometimes its convenient to change the sequential flow of instructions in a program in order to do conditional and/or repetitive tasks. In Assembler, we accomplished this by means of compare and branch statements. The following is an example of how this is done in Assembler:
CLI MI0ACC,C'A'
BE LABEL0001
MVC EBW000,MI0ACC
B LABEL0002
LABEL0001 EQU *
Like Assembler, "C" also provides a means to compare data elements and then execute or skip certain instructions based upon the results of the comparison. This is accomplished by means of the "if" statement whose format is:
if (expression)
statement
[else
statement]
The square brackets in the preceding format indicates that the "else" clause is optional. The "expression" clause refers to a logical expression in "C" which evaluates to either a "1" (TRUE) or "0" (FALSE). When "expression" evaluates to "1", the statement following the "if" clause will be executed. When "expression" evaluates to "0", the statement following the "if" clause will NOT be executed; instead, the "statement" following the "else" will be executed should the "else" clause be present.
In the format above and in later ones, the "statement" clauses can represent one or more actual "C" language statements -- including another control statement. When it represents multiple statements that need to be executed, these statements must be preceded and followed by a left and right curly brace as shown:
if (expression)
{
statement(s)
}
[else
{
statement(s)
} ]
Logical Operators
It's important now to take a brief detour from our look at control statements in
"C" and to take a look at symbols in "C" know as logical operators.
Logical operators are important because the "C" language provides them so that
they can be used in expressions within control statements. A logical operator is used to
do comparison between two items of data. Listed below are the logical operators supported
in "C" and examples of using them in an "if" statement.
Operator | Meaning | Example |
! | Logical NOT | if (!TRUE) |
> | Greater than | if (value1 > value2) |
< | Less than | if (value1 < value2) |
== | Equality test | if (value1 == value2) |
>= | Greater than OR equal to | if (value1 >= value2) |
<= | Less than OR equal to | if (value1 <= value2) |
!= | Not equal to | if (value1 != value2) |
&& | Logical AND | if (value1==1) && (value2==1) |
|| | Logical OR | if (value1==1) || (value2==1) |
As can be seen in the last two examples in the preceding table, you can combine multiple tests in an expression. However, if this is done, it means that the entire expression must evaluate to a "1" before the statement(s) following the "if" clause will be executed.
Now using the information in the preceding paragraphs, we can rewrite the aforementioned Assembler code statements to look like the following "C" statements:
if (mi0acc[0] = = 'A') /*Read: If mi0acc[0= is a character 'A', */
ebw000 = mi0acc[0]; /* Then, Save it to the ebw000 work area.*/
THE "while" & "do" CONTROL STATEMENTS
In Assembler, when you want to execute a series of instructions more than once, you either made use of some kind of unconditional branch instruction or a branch-and-count instruction. Here are two such examples:
Example #1
LABEL0001 EQU *
CLI 0(R2),C'A'
BE LABEL0001
LA R2,1(,R2)
B LABEL0001
LABEL0002 EQU *
Example #2
LABEL0001 EQU *
AR R2,R3
BCT R5, LABEL0001
LABEL0002 EQU *
The preceding statements are commonly referred to as "looping" instructions. "C" offers the "while" and "do" control statements to provide the same kind of functionality seen in the first Assembler looping example. Like in Assembler, these instructions can repetitively execute a group of statements as long as the values in their control statement expressions remain true (i.e., non-zero). The format for these statements are:
while (expression) do
statement statement
while (expression)
The difference between the two control statements is that "while" will only execute the first time if "expression" is true. However, the "do-while" combination always executes at least once and evaluates "expression" at the end of each execution of "statement". As with the "if" control statement format, the "statement" clauses can represent one or multiple actual "C" statements; again -- they must be enclosed between left and right curly braces if more than one statement is present.
An example of using both statement follows:
while (value1 < value2) /*If value1 is less than value two,*/
value1++; /*execute this statement. */
do /*Decrement value1 at least once and */
value1-- /*continue to do so if its still */
while (value1 > value2); /*greater than value2. */
THE "for" CONTROL STATEMENT
The last "C" control statement we'll look at is the "for" statement. It provides functionality similar to the BCT statement loop in the preceding example #2. However, the "for" statement's counter value appears as the first statement in the sequence of instructions rather than at the end. A "for" loop has the following format:
for([initial-expression];[conditional-expression];[loop-expression])
statement;
As you can see, this statement can have up to three different expressions within its clause. The "initial-expression" clause is used to establish the beginning value that will be used to control the "for" loop. The "conditional-expression" clause is used to determine when the "for" loop should stop executing its statements and will do so if "conditional expression" evaluates to "0" (or False). The "loop-expression" is where the counter value is modified so that "conditional-expression" eventually evaluates to "0" (or False).
Like BCT or BCTR, the "for" statement is used to execute the statement(s) in its body a specific number of times. The following is an example of a "for" statement. It accumulates "value1" into "result" until "value1" is no longer less than "value2".
for (value1=1;value1 < value2; value1++)
result=result + value1;
ASSEMBLER-TO-"C" EQUIVALENT FUNCTIONS
As may you realize by now, most of the instructions and macros you used in Assembler are not needed in "C". However, there are a few functions in "C" that work similar to instructions in Assembler which would be a good idea to learn about. Below, I've listed a table of functions in "C" (with their Assembler equivalents) which you might find useful and familiar later.
"C" Function | Assembler Equivalent(s) | Meaning |
Sizeof | L'(Some Fieldname) | Returns the number bytes used by a field |
Memcpy | MVC; MVCL; MVI | Copy data from one location to another |
Memcmp | CLC; CLCL; CLI | Compares data at two locations; returns 0 or 1 |
Sprintf | PACK; UNPK; ED | Formats data into displayable form |
Sscanf | CVB; CVD; etc. | Converts data from one form to another |
Memset | ZAP; XC; X; XI | Sets a data area to all zeroes |
Getcc | GETCC | Allocation of core blocks |
Crusa | CRUSA | Releasing core blocks |
Levtest | LEVTA | Testing levels for core blocks |
The following examples show the use of three of these functions. For each
example assume the following declaration has been made:
char string1[10],string2[10];
short len=10;
Example 1: Demonstrates usage of the memcpy function.
memcpy(string1,string2,len) /*Copy string2 to string1 for number of bytes specified in len */
Example 2: Demonstrates usage of "memcmp" function. This function compares two variables for the length defined in the third parameter. The "memcmp" returns 0 if the two variables are equal.
if (memcmp(string1,string2,len) == 0)
value1 = value2;
else
value2 = value1;
Example 3: Demonstrates the usage of "memset" function. This function is used to initialize a variable to the character in the second parameter for number of bytes specified in the third parameter(len).
memset(string1,'\0',len); /*set string1 to binary zeroes*/
memset(string2,'A',len); /*set string2 to character A's*/
For details on using these "C" functions, refer to your IBM C Programmers Guide manual (or another "C" instruction manual). Also, don't forget that a lot of the TPF macros have "C" equivalents described in the IBM TPF C/C++ Language Support manual. Please refer to those manuals or other similar documentation for details on using the above macros and others.
This concludes our "fast-track" exposure course for moving from TPF Assembler to ISO-C. For more information on learning ISO-C in the TPF environment, contact your local IBM sales representative or surf the web at http://www.s390.ibm.com/products/tpf.
QUIZ - Part 3
EXERCISE
1. Convert the following Assembler programs to "C" functions.
Note 1: You'll have to research the format of the equivalent "C" crusa function on your own.
Note 2: When using ECB-related fields in "C", precede all variable names with "ecbptr()->" (i.e., ecbptr()->ebw000).
Note 3: Use the sizeof() function to determine the size of a field name for memcpy. (i.e., memcpy(fieldname1,fieldname2,sizeof(fieldname1));)
BEGIN
NAME=XYZ1,VERSION=A0
**********************************************************************
*THE PURPOSE OF THIS PROGRAM IS TO CHECK THE CHARACTER IN THE 7TH
*
*POSITION OF THE INPUT MESSAGE. IF ITS A 'Y' FOR YES, THEN WIPE OUT
*
*THE PASSENGER NAME CURRENTLY BEING WORKED UPON. OTHERWISE,
*
*JUST EXIT AND RETURN.
*
**********************************************************************
MI0MI
REG=R1
PN0NR
REG=R3
*
CRUSA
S0=4
RELEASE
LEVEL 4 BLOCK IF ANY
*
L
R1,CE1CR0
BASE THE INPUT BLOCK
L
R3,CE1CR2
BASE THE PASSENGER NAME BLOCK
XR
R4,R4
ZERO OUT
THIS REGISTER
AH
R4,MI0CCT
GET THE NUMBER OF BYTES PASSED
LTR
R4,R4
IS R4 ZERO?
BE
SETERROR
YES, THEN GO EXIT
CLI
MI0ACC,C'Y'
ZERO OUT THE CURRENT PASSENGER NAME ?
BE
ZAPNAME
IF 'Y', THEN GO TO ZAP NAME
*
ENTRC
ABCD
INVOKE ABCD TO DO
THE COPY
*
B
EXITHERE
GO TO EXIT
*
ZAPNAME
DS
0H
XC
PN0NM(L'256),PN0NM
ZERO OUT THE CURRENT NAME RECORD
B
EXITHERE
*
SETERROR
DS
0H
MVI
EBSW01,C'E'
INDICATE AN ERROR OCCURRED
*
EXITHERE
DS
0H
BACKC
,
*
LTORG
,
FINIS
XYZ1
END
,
BEGIN
NAME=ABCD,VERSION=A0
**********************************************************************
*THIS PROGRAM IS CALLED FROM XYZ1 TO COPY ITEMS FROM EBW WORK AREA*
**********************************************************************
*
MI0MI
REG=R1
PN0NR
REG=R3
*
MVC
PN0LST,EBW000
COPY IN LAST NAME (20
Bytes)
MVC
PN0FST,EBW020
COPY FIRST NAME (15
Bytes)
MVC
PN0PHN,EBW035
COPY PHONE NUMBER (12 Bytes)
MVC
PN0FLT,EBW047
COPY FLIGHT NUMBER (4
Bytes)
*--------------------------------------------------------------------*
* Now, clear out the EBW work
area.
*
*--------------------------------------------------------------------*
XC
EBW000(L'PN0LST),EBW000
XC
EBW020(L'PN0FST),EBW020
XC
EBW035(L'PN0PHN),EBW035
XC
EBW047(L'PN0FLT),EBW047
*
BACKC
,
LTORG
FINIS
ABCD
END
ANSWERS TO THE QUIZ AND EXERCISE CAN BE FOUND AT: http://www.robisoft.com