Chapter 17 Quiz: Subprograms and the CALL Statement
Test your understanding of COBOL subprograms, the CALL statement, and modular programming concepts. Each question is followed by a hidden answer -- try to answer before revealing it.
Question 1
What is the difference between a static CALL and a dynamic CALL in COBOL?
Show Answer
A **static CALL** uses a literal program name (e.g., `CALL 'MYSUB'`) and is resolved at link-edit time. The subprogram's object code is included in the same load module as the caller, resulting in a larger load module but faster execution since there is no runtime load overhead. A **dynamic CALL** either uses a variable (e.g., `CALL WS-PROG-NAME`) or uses a literal with the DYNAM compiler option. The subprogram is located and loaded from a load library at runtime. This produces a smaller initial load module and allows subprograms to be replaced without re-linking the main program, but incurs a small runtime load overhead on the first call.Question 2
Which IBM Enterprise COBOL compiler option forces all CALL 'literal' statements to be treated as dynamic calls?
A) NOCALL B) DYNAM C) DYNAMIC D) CALLRES
Show Answer
**B) DYNAM** The DYNAM compiler option causes all CALL statements with literal program names to be resolved dynamically at runtime rather than statically at link-edit time. The opposite option, NODYNAM, is the default on most systems and causes literal calls to be resolved statically. Note that CALL with an identifier (variable) is always dynamic regardless of this option.Question 3
What section of the DATA DIVISION is used in a called program to define the parameters it receives from the calling program?
Show Answer
The **LINKAGE SECTION**. Data items defined in the LINKAGE SECTION describe the layout of memory that is owned by the calling program. The LINKAGE SECTION does not allocate its own memory; instead, it provides a template for accessing the caller's data. Each 01-level or 77-level item in the LINKAGE SECTION that is named in the PROCEDURE DIVISION USING clause corresponds to a parameter passed by the caller.Question 4
In the following code, what will be the value of WS-AMOUNT in the calling program after the CALL returns?
* Calling program:
01 WS-AMOUNT PIC 9(05) VALUE 10000.
CALL 'MYSUB' USING BY CONTENT WS-AMOUNT
* Called program:
LINKAGE SECTION.
01 LS-AMOUNT PIC 9(05).
PROCEDURE DIVISION USING LS-AMOUNT.
ADD 5000 TO LS-AMOUNT
GOBACK.
Show Answer
WS-AMOUNT will still be **10000** (unchanged). When a parameter is passed BY CONTENT, the compiler creates a temporary copy of the data and passes the address of that copy to the subprogram. The subprogram modifies the copy (adding 5000 to make it 15000), but the caller's original WS-AMOUNT is never touched. This is the purpose of BY CONTENT: protecting the caller's data from modification by the called program.Question 5
What happens when a subprogram executes STOP RUN instead of GOBACK?
Show Answer
**STOP RUN** terminates the entire **run unit** -- the main program and all active subprograms in the call chain. Control does not return to the calling program. The application ends immediately. This is almost never the desired behavior in a subprogram. The correct statement is **GOBACK**, which returns control to the statement following the CALL in the calling program, allowing the run unit to continue. STOP RUN should only be used in the main program.Question 6
True or False: A subprogram's WORKING-STORAGE values are reinitialized to their VALUE clauses every time the subprogram is called.
Show Answer
**False.** By default, WORKING-STORAGE values persist between calls. They are initialized to VALUE clauses only when the subprogram is first loaded. On subsequent calls, WORKING-STORAGE retains the values from the previous invocation. This persistence continues until: 1. The subprogram is CANCELed (causing reinitialization on the next call), or 2. The subprogram is declared with `IS INITIAL` in its PROGRAM-ID (causing reinitialization on every call).Question 7
What does the CANCEL statement do, and can it be used on a statically linked subprogram?
Show Answer
The **CANCEL** statement releases a dynamically loaded subprogram from memory. The next time the subprogram is called, it will be reloaded from the load library, and its WORKING-STORAGE will be reinitialized to the values specified in VALUE clauses. CANCEL **cannot** be meaningfully used on a statically linked subprogram because the subprogram is physically part of the same load module as the main program. It is not separately loaded and cannot be separately unloaded. Attempting to CANCEL a statically linked program has no effect.Question 8
In the following CALL statement, what are the passing modes for each parameter?
CALL 'PROCESS' USING WS-INPUT-REC
BY CONTENT WS-CONFIG
WS-OPTIONS
BY REFERENCE WS-OUTPUT
Show Answer
- **WS-INPUT-REC**: BY REFERENCE (the default, since no mode is specified) - **WS-CONFIG**: BY CONTENT (explicitly specified) - **WS-OPTIONS**: BY CONTENT (the BY CONTENT carries forward from WS-CONFIG until a new mode is specified) - **WS-OUTPUT**: BY REFERENCE (explicitly specified) The passing mode applies to all subsequent parameters until a new mode keyword appears.Question 9
What is the purpose of the RETURNING clause in a CALL statement, and when was it introduced?
Show Answer
The **RETURNING** clause, introduced in **COBOL 2002**, provides a structured way to return a value from a called program. In the called program, the RETURNING clause is specified on the PROCEDURE DIVISION:PROCEDURE DIVISION USING LS-INPUT RETURNING LS-RESULT.
In the calling program:
CALL 'MYSUB' USING WS-INPUT RETURNING WS-RESULT
It is an alternative to using the RETURN-CODE special register. The advantages are that the return value is explicitly part of the interface definition, it can be any data type (not just numeric), and it makes the subprogram's contract more self-documenting.
Question 10
What is the RETURN-CODE special register, and what are the conventional values used on IBM mainframes?
Show Answer
**RETURN-CODE** is a special register that serves as a numeric communication channel between calling and called programs. The called program sets RETURN-CODE before issuing GOBACK, and the calling program examines it after the CALL. The conventional IBM mainframe return code values are: | Value | Meaning | |-------|---------| | 0 | Success; no errors | | 4 | Warning; processing completed with minor issues | | 8 | Error; processing may be incomplete | | 12 | Severe error; significant problems | | 16 | Critical error; processing could not continue | These values are incremented by 4 by convention, though this is a guideline, not a technical requirement.Question 11
What is the difference between BY CONTENT and BY VALUE?
Show Answer
**BY CONTENT**: The compiler creates a temporary copy of the data and passes the **address** of that copy. The subprogram receives a pointer to the copy and can modify it, but changes do not affect the caller's original data. This works with any data type. **BY VALUE**: The actual **value** is placed directly on the call stack (not an address). This is the calling convention used by C and other non-COBOL languages. BY VALUE is restricted to binary integer types (COMP, COMP-5, BINARY) and cannot be used with group items. Both protect the caller's data, but they use different mechanisms: BY CONTENT passes an address (of a copy), while BY VALUE passes the value itself.Question 12
Given this nested program structure, which program(s) can call UTILITY?
PROGRAM-ID. PARENT.
PROGRAM-ID. WORKER-A.
END PROGRAM WORKER-A.
PROGRAM-ID. WORKER-B.
END PROGRAM WORKER-B.
PROGRAM-ID. UTILITY IS COMMON.
END PROGRAM UTILITY.
END PROGRAM PARENT.
Show Answer
All three programs can call UTILITY: 1. **PARENT** can call UTILITY because PARENT is the containing (parent) program, and a parent can always call any of its directly contained programs. 2. **WORKER-A** can call UTILITY because UTILITY has the COMMON clause, which makes it callable by sibling programs (programs contained in the same parent). 3. **WORKER-B** can call UTILITY for the same reason as WORKER-A. Without the COMMON clause, only PARENT would be able to call UTILITY. The COMMON clause specifically enables sibling-to-sibling calls.Question 13
What is the GLOBAL clause, and how does it differ from passing data through the USING clause?
Show Answer
The **GLOBAL** clause makes a data item defined in a parent program visible to all its contained (nested) programs without explicitly passing it as a parameter.01 WS-SHARED-DATA PIC X(100) IS GLOBAL.
Differences from USING:
- **GLOBAL** requires no parameter on the CALL statement -- the data is simply available
- **GLOBAL** only works with nested programs, not external subprograms
- **GLOBAL** creates implicit coupling -- changes to the data structure affect all nested programs
- **USING** is explicit -- each caller and callee must declare the parameters
- **USING** works with both nested and external programs
- **USING** provides better encapsulation and makes dependencies visible
GLOBAL is convenient for shared counters, flags, or configuration data within a nested program structure, but should be used sparingly because it can create tight coupling.
Question 14
What is the IS INITIAL clause, and when would you use it?
Show Answer
The **IS INITIAL** clause on PROGRAM-ID causes a subprogram's WORKING-STORAGE to be reinitialized to VALUE clauses on **every** invocation, as if the program were being called for the first time.PROGRAM-ID. MYSUB IS INITIAL.
Use IS INITIAL when:
- The subprogram must have no "memory" of previous calls
- Persistent state would cause bugs (e.g., accumulators that should start at zero each time)
- You want guaranteed predictable behavior regardless of calling sequence
- The cost of reinitialization is acceptable for your performance requirements
Without IS INITIAL, the only way to reset WORKING-STORAGE is to CANCEL the subprogram (which only works for dynamic calls).
Question 15
Write the CALL statement and the corresponding PROCEDURE DIVISION USING clause for a subprogram that receives three parameters: an employee record BY REFERENCE, a tax rate BY CONTENT, and a result area BY REFERENCE.
Show Answer
**In the calling program:** CALL 'TAXCALC' USING BY REFERENCE WS-EMPLOYEE-REC
BY CONTENT WS-TAX-RATE
BY REFERENCE WS-RESULT-AREA
**In the called program:**
LINKAGE SECTION.
01 LS-EMPLOYEE-REC.
05 ...
01 LS-TAX-RATE PIC 9V9(04).
01 LS-RESULT-AREA.
05 ...
PROCEDURE DIVISION USING LS-EMPLOYEE-REC
LS-TAX-RATE
LS-RESULT-AREA.
Note: The BY CONTENT and BY REFERENCE keywords are only specified on the caller's CALL statement. The subprogram's PROCEDURE DIVISION USING does not specify the passing mode (except for BY VALUE, which must be specified in both places). The subprogram receives addresses in all cases -- the passing mode semantics are handled by the caller and compiler.
Question 16
What is the ON EXCEPTION phrase in a CALL statement, and when does it trigger?
Show Answer
The **ON EXCEPTION** phrase (also known as ON OVERFLOW in older standards) specifies imperative statements to execute when the called program cannot be found or loaded. It triggers when: - A dynamically called program does not exist in the search path (STEPLIB, JOBLIB, etc.) - The program name is invalid - There is insufficient memory to load the program Example: CALL WS-PROG-NAME USING WS-DATA
ON EXCEPTION
DISPLAY 'Cannot load program: ' WS-PROG-NAME
MOVE 99 TO WS-STATUS
NOT ON EXCEPTION
MOVE RETURN-CODE TO WS-STATUS
END-CALL
ON EXCEPTION is particularly important for dynamic calls, where the program's availability is not guaranteed at link time. For static calls, the linker would catch a missing program before execution.
Question 17
How many parameters can a COBOL CALL statement pass?
Show Answer
The COBOL standard does not specify a hard limit on the number of parameters. However, practical limits exist: - **IBM Enterprise COBOL**: Supports up to **4096** parameters in the USING clause - **GnuCOBOL**: Supports a large number (implementation-defined) - **Micro Focus COBOL**: Supports up to 252 parameters (older versions may have lower limits) In practice, if you need more than 5-7 parameters, it is better to bundle them into one or more group items. Passing a single group item with 20 fields is better than passing 20 individual parameters -- it is easier to manage, less error-prone, and the interface is more maintainable.Question 18
Explain the difference between WORKING-STORAGE SECTION and LOCAL-STORAGE SECTION in the context of a recursive program.
Show Answer
In a program with the RECURSIVE attribute: - **WORKING-STORAGE SECTION**: Allocated **once** and **shared** across all recursive invocations. If the program calls itself, all invocations see and modify the same WORKING-STORAGE data. Changes made in a deeper recursion level are visible to shallower levels. - **LOCAL-STORAGE SECTION**: Allocated **separately** for each invocation. Each recursive call gets its own copy of LOCAL-STORAGE data. Values in one invocation are independent of values in other invocations. LOCAL-STORAGE is reinitialized per VALUE clauses on each invocation. For recursive programs, you typically need LOCAL-STORAGE for data that must be unique to each recursion level (loop counters, intermediate results), and WORKING-STORAGE only for data that should be shared (global counters, configuration settings).Question 19
A COBOL program is compiled with NODYNAM. The program contains both CALL 'STATIC1' and CALL WS-DYN-NAME. What type of call is each?
Show Answer
- `CALL 'STATIC1'` is a **static call** because NODYNAM is in effect and the program name is a literal. The subprogram will be resolved at link-edit time and must be included in the link step. - `CALL WS-DYN-NAME` is a **dynamic call** because the program name is specified as an identifier (variable). A CALL with an identifier is **always** dynamic, regardless of the DYNAM/NODYNAM compiler option. The subprogram will be located and loaded at runtime. The DYNAM/NODYNAM option only affects CALL statements that use literals. It has no effect on CALL statements that use identifiers.Question 20
What is the difference between EXIT PROGRAM and GOBACK in a subprogram?
Show Answer
Both EXIT PROGRAM and GOBACK return control to the calling program when executed in a called subprogram. The key differences are: **EXIT PROGRAM:** - In a **called program**: Returns control to the caller (same as GOBACK) - In a **main program**: Has no effect; execution continues to the next statement - This is an older construct from COBOL-74/85 **GOBACK:** - In a **called program**: Returns control to the caller - In a **main program**: Terminates the run unit (same as STOP RUN) - Works correctly in both contexts - Introduced in COBOL-85 and is the recommended modern practice Most modern COBOL shops standardize on GOBACK because it works correctly regardless of whether the program is used as a main program or a subprogram. EXIT PROGRAM is still found in older code but is being phased out in favor of GOBACK.Question 21
What compiler listing option can you use on IBM Enterprise COBOL to see how parameters are laid out in memory?
A) LIST B) MAP C) XREF D) OFFSET
Show Answer
**B) MAP** The MAP compiler option produces a Data Division Map in the compiler listing that shows the memory offset, length, and attributes of every data item, including LINKAGE SECTION items. This is invaluable for verifying that parameter structures in the calling and called programs are properly aligned. The LIST option produces an assembler listing, XREF produces a cross-reference listing of data names and procedure names, and OFFSET produces a condensed procedure listing with offsets. While LIST can also show parameter layout details, MAP is the most direct way to verify data item sizes and offsets.Question 22
A programmer receives a S0C4 abend when a subprogram tries to access a LINKAGE SECTION item. What are the three most likely causes?
Show Answer
The three most likely causes of an S0C4 (protection exception) when accessing LINKAGE SECTION items are: 1. **Parameter count mismatch**: The calling program passes fewer parameters than the subprogram expects. The subprogram tries to access a parameter that was never passed, resulting in an invalid address. For example, the caller passes 2 parameters but the subprogram's USING clause names 3. 2. **Parameter size mismatch**: The LINKAGE SECTION item is larger than the caller's data item. When the subprogram accesses bytes beyond the caller's allocated storage, it reads or writes into unallocated or protected memory. For example, the caller passes PIC X(10) but the LINKAGE SECTION describes PIC X(100). 3. **Subprogram is called without USING**: The CALL statement omits the USING clause entirely, but the subprogram expects parameters. The LINKAGE SECTION addresses are undefined (typically zeros or garbage), causing a protection exception on first access. Other less common causes include passing a BY VALUE parameter where BY REFERENCE was expected, or calling the wrong subprogram entirely.Question 23
What is the significance of the ENTRY statement in COBOL, and how does it relate to subprograms?
Show Answer
The **ENTRY** statement provides an alternate entry point into a COBOL subprogram. It allows a single physical program to be called by different names, potentially with different parameter lists: PROGRAM-ID. DATEUTIL.
LINKAGE SECTION.
01 LS-DATE PIC X(10).
01 LS-RESULT PIC 9(02).
01 LS-JULIAN PIC 9(07).
PROCEDURE DIVISION.
ENTRY 'DATEVAL' USING LS-DATE LS-RESULT.
PERFORM validate-date
GOBACK.
ENTRY 'DATEJUL' USING LS-DATE LS-JULIAN LS-RESULT.
PERFORM convert-to-julian
GOBACK.
Callers can use `CALL 'DATEVAL'` or `CALL 'DATEJUL'` to enter the same physical program at different points. This was more common in older COBOL; modern practice generally favors separate subprograms or a single subprogram with an operation code parameter. Note that ENTRY is considered obsolete in some newer COBOL standards.
Question 24
In GnuCOBOL, what is the difference between compiling with -x and -m?
Show Answer
- **`-x` (executable)**: Produces a standalone executable program. This is used for the main program that will be run directly from the command line. The output is a native executable file (e.g., `myprog` on Linux, `myprog.exe` on Windows). You can also list subprogram source files on the same command to link them statically: `cobc -x main.cob sub1.cob sub2.cob`. - **`-m` (module)**: Produces a dynamically loadable module (shared library). The output is a `.so` file on Linux or a `.dll` on Windows. This is used for subprograms that will be loaded dynamically at runtime when called. The main program finds and loads these modules by searching the current directory, `COB_LIBRARY_PATH`, and other configured locations. Summary: Use `-x` for the main program (or for static linking), and `-m` for subprograms that should be dynamically loaded.Question 25
Why is it important to use copybooks for parameter structures, and what problem does this prevent?