When one COBOL program calls another with CALL ... USING, it must choose how each argument is passed: by reference, by content, or by value. That choice determines whether the called program shares the same storage as the caller or works on a copy, and whether the caller sees any changes the subprogram makes. This page explains the three mechanisms, how they differ, when to use each, and how the LINKAGE SECTION in the called program must match.
When you ask a friend to do a task, you might hand them the actual thing (e.g. your notebook) or a copy (e.g. a photocopy). If you hand the real notebook, whatever they write in it is in your notebook too. If you hand a copy, they can scribble on the copy and your original stays the same. Parameter passing in COBOL is like that: BY REFERENCE means the subprogram gets the "real" data (same storage), so changes show up in the caller. BY CONTENT and BY VALUE mean the subprogram gets a copy, so the caller's data does not change no matter what the subprogram does.
COBOL defines three ways to pass data in the USING phrase of the CALL statement. You can mix them in one CALL: some arguments BY REFERENCE, others BY CONTENT, others BY VALUE. The called program declares the parameters in its LINKAGE SECTION and in PROCEDURE DIVISION USING in the same order. The passing mechanism affects both what the subprogram can do and whether the caller sees updates.
| Method | Meaning | When to use | Literals allowed? |
|---|---|---|---|
| BY REFERENCE | Address of the argument is passed. Caller and subprogram share the same storage. Changes in the subprogram are visible to the caller. | Output or input-output parameters; large data to avoid copying. Default if not specified. | No |
| BY CONTENT | A copy of the value is passed. The subprogram can modify its copy; the caller's data is never changed. | Input-only data that must not be altered, or when passing literals. | Yes |
| BY VALUE | The value is passed (implementation-defined). Subprogram gets a temporary copy; changes do not affect the caller. Often used for C/C++ interop. | Small values, literals, or calling non-COBOL programs that expect BY VALUE. | Yes |
With BY REFERENCE, the calling program passes the address of the argument. The subprogram does not get a copy; it uses the same storage as the caller. So when the subprogram moves a value into the parameter or modifies it in any way, the change is visible in the calling program as soon as the subprogram returns. If you do not specify BY REFERENCE, BY CONTENT, or BY VALUE for a parameter, BY REFERENCE is assumed. Use BY REFERENCE when the subprogram is meant to update the argument (output or input-output), or when you want to avoid copying large structures. You cannot pass a literal BY REFERENCE because a literal has no address.
12345678910*> Caller 01 WS-AMOUNT PIC 9(7)V99. 01 WS-TAX PIC 9(7)V99. MOVE 1000.00 TO WS-AMOUNT CALL 'CALCTAX' USING WS-AMOUNT, WS-TAX *> After return, WS-TAX has been set by CALCTAX (BY REFERENCE) *> Explicit form (same as default): CALL 'CALCTAX' USING BY REFERENCE WS-AMOUNT, BY REFERENCE WS-TAX
In the called program, the LINKAGE SECTION items LNK-AMOUNT and LNK-TAX map to WS-AMOUNT and WS-TAX. A MOVE to LNK-TAX in the subprogram updates the caller's WS-TAX.
With BY CONTENT, the calling program passes a copy of the value of the argument. The subprogram receives that copy in its parameter (still defined in LINKAGE SECTION). The subprogram can read and even modify its parameter, but any modification affects only the copy. The caller's original data is never changed. BY CONTENT is useful when you want to pass input-only data that the subprogram must not alter, or when you need to pass a literal (e.g. BY CONTENT "YES" or BY CONTENT 0). Passing BY CONTENT can involve copying data, so for very large items some implementations may still pass an address of a temporary copy; either way, the semantic guarantee is that the caller's data is not modified.
123456*> Caller: pass a literal and a copy of a variable CALL 'VALIDATE' USING BY CONTENT 'ACTIVE', BY CONTENT WS-CODE *> In VALIDATE, changing the parameter does not change WS-CODE *> LINKAGE SECTION in called program still defines the parameters *> but they refer to temporary copies, not the caller's storage
Some compilers support BY CONTENT LENGTH OF identifier to pass the length of a data item (e.g. from the LENGTH special register). That way the subprogram receives both the data (e.g. BY REFERENCE) and a copy of its length (BY CONTENT), which is useful for variable-length or buffer handling.
With BY VALUE, the value of the argument is passed rather than a reference. The subprogram receives a temporary copy; it can change that copy but the caller's argument is never affected. Semantics can be implementation-dependent. BY VALUE is commonly used when calling non-COBOL programs (e.g. C or C++) that use pass-by-value linkage conventions. It is also valid for passing small values or literals when you do not want the subprogram to modify the caller's data. On some platforms, BY VALUE ADDRESS OF identifier is used to pass a pointer to a C/C++ routine that expects a pointer argument.
1234*> Caller: pass a numeric literal and a small integer CALL 'C-ROUTINE' USING BY VALUE 1, BY VALUE WS-FLAG *> Subprogram receives copies; changing them does not change WS-FLAG
If you call C or C++ code, check your compiler documentation for how BY VALUE and BY VALUE ADDRESS OF are represented (e.g. in registers or on the stack) so they match the foreign routine's expectations.
You can specify a different mechanism for each argument. The order of arguments in the CALL must match the order of parameters in the called program's PROCEDURE DIVISION USING and LINKAGE SECTION. The mechanism does not change the order or the number of parameters.
12345678CALL 'ERRPROC' USING BY REFERENCE WS-BUFFER BY CONTENT LENGTH OF WS-BUFFER BY CONTENT 'ERROR' *> ERRPROC gets: 1) reference to WS-BUFFER (can update it) *> 2) copy of the length (cannot change caller's LENGTH) *> 3) copy of the literal 'ERROR'
The called program must define every parameter it receives in the LINKAGE SECTION. Each 01- or 77-level item corresponds to one argument in the CALL, in the same order. The LINKAGE SECTION does not allocate storage; it describes the layout of the data that the caller passed. So the first LINKAGE item maps to the first USING argument, the second to the second, and so on. The PICTURE (and length) of each linkage item should match the caller's argument to avoid misinterpretation of data. If the caller passes BY REFERENCE, the linkage item describes the shared storage; if BY CONTENT or BY VALUE, the linkage item typically describes the temporary copy provided by the system.
123456789101112*> Called program ERRPROC DATA DIVISION. LINKAGE SECTION. 01 LNK-BUFFER PIC X(100). 01 LNK-LEN PIC 9(4). 01 LNK-MESSAGE PIC X(5). PROCEDURE DIVISION USING LNK-BUFFER, LNK-LEN, LNK-MESSAGE. MAIN. *> Use LNK-BUFFER, LNK-LEN, LNK-MESSAGE in order GOBACK.
Some compilers allow you to specify the passing mechanism in the called program as well (e.g. PROCEDURE DIVISION USING BY REFERENCE LNK-BUFFER BY CONTENT LNK-LEN). When specified, it should match the caller; when omitted, the default BY REFERENCE applies. Check your compiler manual.
Literals (numeric or alphanumeric) have no storage address in the caller, so they cannot be passed BY REFERENCE. Use BY CONTENT or BY VALUE. For example, BY CONTENT "ACTIVE" or BY VALUE 0 passes a copy of the literal. The LENGTH OF special register (on compilers that support it) gives the length in bytes of a data item. To pass that length to a subprogram, use BY CONTENT LENGTH OF identifier so the subprogram receives a copy of the length value. That is useful when the subprogram needs to know how long a buffer is without modifying the caller's data.
The CALL statement can include RETURNING identifier so the caller receives a single return value from the subprogram. RETURNING is separate from USING: USING passes arguments in and out (depending on mechanism); RETURNING is the function-style result. The subprogram sets the return value (in the item named in PROCEDURE DIVISION ... RETURNING) before executing GOBACK or EXIT PROGRAM, and that value is copied back to the caller's RETURNING identifier. So the subprogram can return one value via RETURNING and optionally modify multiple arguments via BY REFERENCE parameters.
1. If you do not specify BY REFERENCE, BY CONTENT, or BY VALUE, parameters are passed:
2. You want to pass the number 100 to a subprogram without allowing it to change the caller's data. You should use:
3. The subprogram modifies a parameter but the caller does not see the change. The parameter was likely passed: