Translate

Mostrar mensagens com a etiqueta dump hexadecimal. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta dump hexadecimal. Mostrar todas as mensagens

quinta-feira, 23 de julho de 2026

COMP-4 e COMP-5 sem Mistérios — Parte II : Laboratório Prático com TRUNC(STD), TRUNC(OPT), TRUNC(BIN), JCL, Hexadecimal, Testes e Pequenos Acidentes Controlados

Bellacosa Maifnrame com laboratorio pratico cobol comp-4  comp-5


☕ Um Café no Bellacosa Mainframe

COMP-4 e COMP-5 sem Mistérios — Parte II

Laboratório Prático com TRUNC(STD), TRUNC(OPT), TRUNC(BIN), JCL, Hexadecimal, Testes e Pequenos Acidentes Controlados

Na primeira parte, descobrimos que COMP-4 e COMP-5 guardam números em formato binário, mas não fazem exatamente o mesmo contrato com o compilador.

Agora chegou a hora de abandonar a segurança filosófica da teoria e entrar no laboratório.

Nesta segunda parte, faremos o seguinte:

  • criaremos um programa COBOL de testes;

  • compilaremos o mesmo fonte com TRUNC(STD), TRUNC(OPT) e TRUNC(BIN);

  • executaremos três load modules diferentes;

  • mostraremos o conteúdo decimal e hexadecimal dos campos;

  • compararemos COMP-4 com COMP-5;

  • testaremos valores acima do limite do PICTURE;

  • provocaremos truncamentos controlados;

  • analisaremos resultados estranhos;

  • trabalharemos com REDEFINES;

  • estudaremos ON SIZE ERROR;

  • construiremos exercícios para o programador padawan.

O objetivo não é decorar tabelas.

O objetivo é aprender a olhar para um campo COBOL e perguntar:

Quantos dígitos ele declara, quantos bytes ele ocupa e qual dessas duas verdades o compilador utilizará nesta operação?


1. Preparando o laboratório

Utilizaremos um programa chamado:

TRUNCLAB

O mesmo fonte será compilado três vezes.

Cada compilação produzirá um load module:

TRNSTD
TRNOPT
TRNBIN

As opções serão:

TRUNC(STD)
TRUNC(OPT)
TRUNC(BIN)

Depois executaremos os três módulos e compararemos o SYSOUT.

A opção TRUNC afeta a maneira como dados BINARY, COMP e COMP-4 são tratados em movimentos e operações aritméticas. Ela não altera o comportamento de itens COMP-5: para esses campos, o compilador sempre aplica a lógica equivalente a TRUNC(BIN). (IBM)


2. Recordando o tamanho dos campos binários

No Enterprise COBOL, o tamanho físico de um campo binário depende da quantidade de dígitos do PICTURE:

Quantidade de dígitosArmazenamento
1 a 42 bytes
5 a 94 bytes
10 a 188 bytes

Assim:

05 CAMPO-A PIC S9(4) COMP-4.

ocupa 2 bytes.

05 CAMPO-B PIC S9(5) COMP-4.

ocupa 4 bytes.

05 CAMPO-C PIC S9(10) COMP-4.

ocupa 8 bytes.

Os números negativos são representados em complemento de dois, e os dados binários no IBM Z são armazenados em ordem big-endian. (IBM)


3. A tabela que o padawan deve ter ao lado do terminal

Campos de 2 bytes com sinal

PIC S9(1) até PIC S9(4)

Capacidade física:

-32768 até +32767

Campos de 2 bytes sem sinal

PIC 9(1) até PIC 9(4)

Capacidade física:

0 até 65535

Campos de 4 bytes com sinal

PIC S9(5) até PIC S9(9)

Capacidade física:

-2147483648 até +2147483647

Campos de 4 bytes sem sinal

PIC 9(5) até PIC 9(9)

Capacidade física:

0 até 4294967295

Essas faixas representam a capacidade nativa utilizada por COMP-5. Em um campo COMP-4, a opção TRUNC poderá determinar se o programa considera a capacidade decimal do PICTURE ou a capacidade física dos bytes. (IBM)


4. Programa COBOL completo do laboratório

Grave o programa a seguir em um membro como:

USER.COBOL(TRUNCLAB)

O programa contém diferentes grupos de testes.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. TRUNCLAB.

       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SOURCE-COMPUTER. IBM-Z.
       OBJECT-COMPUTER. IBM-Z.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

      *---------------------------------------------------------------*
      * IDENTIFICACAO DO LABORATORIO                                  *
      *---------------------------------------------------------------*

       01  WS-TITULO.
           05 FILLER PIC X(45)
              VALUE 'LABORATORIO COBOL - COMP-4, COMP-5 E TRUNC'.

       01  WS-SEPARADOR PIC X(70) VALUE ALL '-'.

      *---------------------------------------------------------------*
      * CAMPOS DE EDICAO                                              *
      *---------------------------------------------------------------*

       01  WS-EDIT-SIGNED    PIC -ZZZ,ZZZ,ZZZ,ZZZ,ZZZ,ZZ9.
       01  WS-EDIT-UNSIGNED  PIC ZZZ,ZZZ,ZZZ,ZZZ,ZZZ,ZZ9.

      *---------------------------------------------------------------*
      * TESTE 1 - HALFWORD COM SINAL                                  *
      *---------------------------------------------------------------*

       01  WS-T1-ENTRADA        PIC S9(9) COMP-5 VALUE ZERO.

       01  WS-T1-COMP4.
           05 WS-T1-C4          PIC S9(4) COMP-4 VALUE ZERO.

       01  WS-T1-COMP4-RAW REDEFINES WS-T1-COMP4.
           05 WS-T1-C4-BYTES    PIC X(2).

       01  WS-T1-COMP5.
           05 WS-T1-C5          PIC S9(4) COMP-5 VALUE ZERO.

       01  WS-T1-COMP5-RAW REDEFINES WS-T1-COMP5.
           05 WS-T1-C5-BYTES    PIC X(2).

      *---------------------------------------------------------------*
      * TESTE 2 - HALFWORD SEM SINAL                                  *
      *---------------------------------------------------------------*

       01  WS-T2-ENTRADA        PIC 9(9) COMP-5 VALUE ZERO.

       01  WS-T2-COMP4.
           05 WS-T2-C4          PIC 9(4) COMP-4 VALUE ZERO.

       01  WS-T2-COMP4-RAW REDEFINES WS-T2-COMP4.
           05 WS-T2-C4-BYTES    PIC X(2).

       01  WS-T2-COMP5.
           05 WS-T2-C5          PIC 9(4) COMP-5 VALUE ZERO.

       01  WS-T2-COMP5-RAW REDEFINES WS-T2-COMP5.
           05 WS-T2-C5-BYTES    PIC X(2).

      *---------------------------------------------------------------*
      * TESTE 3 - EXEMPLO CLASSICO IBM                                *
      *---------------------------------------------------------------*

       01  WS-T3-ENTRADA        PIC S9(9) COMP-5 VALUE ZERO.

       01  WS-T3-COMP4.
           05 WS-T3-C4          PIC S99 COMP-4 VALUE ZERO.

       01  WS-T3-COMP4-RAW REDEFINES WS-T3-COMP4.
           05 WS-T3-C4-BYTES    PIC X(2).

       01  WS-T3-COMP5.
           05 WS-T3-C5          PIC S99 COMP-5 VALUE ZERO.

       01  WS-T3-COMP5-RAW REDEFINES WS-T3-COMP5.
           05 WS-T3-C5-BYTES    PIC X(2).

      *---------------------------------------------------------------*
      * TESTE 4 - FULLWORD                                            *
      *---------------------------------------------------------------*

       01  WS-T4-ENTRADA        PIC 9(10) COMP-5 VALUE ZERO.

       01  WS-T4-COMP4.
           05 WS-T4-C4          PIC 9(6) COMP-4 VALUE ZERO.

       01  WS-T4-COMP4-RAW REDEFINES WS-T4-COMP4.
           05 WS-T4-C4-BYTES    PIC X(4).

       01  WS-T4-COMP5.
           05 WS-T4-C5          PIC 9(6) COMP-5 VALUE ZERO.

       01  WS-T4-COMP5-RAW REDEFINES WS-T4-COMP5.
           05 WS-T4-C5-BYTES    PIC X(4).

      *---------------------------------------------------------------*
      * TESTE 5 - ARITMETICA                                          *
      *---------------------------------------------------------------*

       01  WS-T5-COMP4.
           05 WS-T5-C4          PIC 9(4) COMP-4 VALUE ZERO.

       01  WS-T5-COMP4-RAW REDEFINES WS-T5-COMP4.
           05 WS-T5-C4-BYTES    PIC X(2).

       01  WS-T5-COMP5.
           05 WS-T5-C5          PIC 9(4) COMP-5 VALUE ZERO.

       01  WS-T5-COMP5-RAW REDEFINES WS-T5-COMP5.
           05 WS-T5-C5-BYTES    PIC X(2).

      *---------------------------------------------------------------*
      * TESTE 6 - SIZE ERROR                                          *
      *---------------------------------------------------------------*

       01  WS-T6-COMP4          PIC 9(4) COMP-4 VALUE ZERO.
       01  WS-T6-COMP5          PIC 9(4) COMP-5 VALUE ZERO.
       01  WS-T6-STATUS         PIC X(20) VALUE SPACES.

      *---------------------------------------------------------------*
      * PROCEDURE DIVISION                                            *
      *---------------------------------------------------------------*

       PROCEDURE DIVISION.

       0000-MAIN.

           DISPLAY WS-SEPARADOR
           DISPLAY WS-TITULO
           DISPLAY WS-SEPARADOR

           PERFORM 1000-TESTE-HALFWORD-SIGNED
           PERFORM 2000-TESTE-HALFWORD-UNSIGNED
           PERFORM 3000-TESTE-IBM-HALFWORD
           PERFORM 4000-TESTE-IBM-FULLWORD
           PERFORM 5000-TESTE-ARITMETICA
           PERFORM 6000-TESTE-SIZE-ERROR

           DISPLAY WS-SEPARADOR
           DISPLAY 'FIM DO LABORATORIO'
           DISPLAY WS-SEPARADOR

           GOBACK.

      *---------------------------------------------------------------*
      * TESTE 1                                                       *
      *---------------------------------------------------------------*

       1000-TESTE-HALFWORD-SIGNED.

           DISPLAY SPACE
           DISPLAY 'TESTE 1 - PIC S9(4), VALOR 30000'
           DISPLAY WS-SEPARADOR

           MOVE 30000 TO WS-T1-ENTRADA
           MOVE WS-T1-ENTRADA TO WS-T1-C4
           MOVE WS-T1-ENTRADA TO WS-T1-C5

           MOVE WS-T1-C4 TO WS-EDIT-SIGNED
           DISPLAY 'COMP-4 DECIMAL : ' WS-EDIT-SIGNED
           DISPLAY 'COMP-4 HEX     : '
                   FUNCTION HEX-OF(WS-T1-C4-BYTES)

           MOVE WS-T1-C5 TO WS-EDIT-SIGNED
           DISPLAY 'COMP-5 DECIMAL : ' WS-EDIT-SIGNED
           DISPLAY 'COMP-5 HEX     : '
                   FUNCTION HEX-OF(WS-T1-C5-BYTES).

      *---------------------------------------------------------------*
      * TESTE 2                                                       *
      *---------------------------------------------------------------*

       2000-TESTE-HALFWORD-UNSIGNED.

           DISPLAY SPACE
           DISPLAY 'TESTE 2 - PIC 9(4), VALOR 60000'
           DISPLAY WS-SEPARADOR

           MOVE 60000 TO WS-T2-ENTRADA
           MOVE WS-T2-ENTRADA TO WS-T2-C4
           MOVE WS-T2-ENTRADA TO WS-T2-C5

           MOVE WS-T2-C4 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 HEX     : '
                   FUNCTION HEX-OF(WS-T2-C4-BYTES)

           MOVE WS-T2-C5 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 HEX     : '
                   FUNCTION HEX-OF(WS-T2-C5-BYTES).

      *---------------------------------------------------------------*
      * TESTE 3                                                       *
      *---------------------------------------------------------------*

       3000-TESTE-IBM-HALFWORD.

           DISPLAY SPACE
           DISPLAY 'TESTE 3 - PIC S99, VALOR 123451'
           DISPLAY WS-SEPARADOR

           MOVE 123451 TO WS-T3-ENTRADA
           MOVE WS-T3-ENTRADA TO WS-T3-C4
           MOVE WS-T3-ENTRADA TO WS-T3-C5

           MOVE WS-T3-C4 TO WS-EDIT-SIGNED
           DISPLAY 'COMP-4 DECIMAL : ' WS-EDIT-SIGNED
           DISPLAY 'COMP-4 HEX     : '
                   FUNCTION HEX-OF(WS-T3-C4-BYTES)

           MOVE WS-T3-C5 TO WS-EDIT-SIGNED
           DISPLAY 'COMP-5 DECIMAL : ' WS-EDIT-SIGNED
           DISPLAY 'COMP-5 HEX     : '
                   FUNCTION HEX-OF(WS-T3-C5-BYTES).

      *---------------------------------------------------------------*
      * TESTE 4                                                       *
      *---------------------------------------------------------------*

       4000-TESTE-IBM-FULLWORD.

           DISPLAY SPACE
           DISPLAY 'TESTE 4 - PIC 9(6), VALOR 1234567891'
           DISPLAY WS-SEPARADOR

           MOVE 1234567891 TO WS-T4-ENTRADA
           MOVE WS-T4-ENTRADA TO WS-T4-C4
           MOVE WS-T4-ENTRADA TO WS-T4-C5

           MOVE WS-T4-C4 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 HEX     : '
                   FUNCTION HEX-OF(WS-T4-C4-BYTES)

           MOVE WS-T4-C5 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 HEX     : '
                   FUNCTION HEX-OF(WS-T4-C5-BYTES).

      *---------------------------------------------------------------*
      * TESTE 5                                                       *
      *---------------------------------------------------------------*

       5000-TESTE-ARITMETICA.

           DISPLAY SPACE
           DISPLAY 'TESTE 5 - ARITMETICA 9000 + 5000'
           DISPLAY WS-SEPARADOR

           MOVE 9000 TO WS-T5-C4
           MOVE 9000 TO WS-T5-C5

           ADD 5000 TO WS-T5-C4
           ADD 5000 TO WS-T5-C5

           MOVE WS-T5-C4 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-4 HEX     : '
                   FUNCTION HEX-OF(WS-T5-C4-BYTES)

           MOVE WS-T5-C5 TO WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 DECIMAL : ' WS-EDIT-UNSIGNED
           DISPLAY 'COMP-5 HEX     : '
                   FUNCTION HEX-OF(WS-T5-C5-BYTES).

      *---------------------------------------------------------------*
      * TESTE 6                                                       *
      *---------------------------------------------------------------*

       6000-TESTE-SIZE-ERROR.

           DISPLAY SPACE
           DISPLAY 'TESTE 6 - ON SIZE ERROR'
           DISPLAY WS-SEPARADOR

           MOVE ZERO TO WS-T6-C4 WS-T6-C5
           MOVE SPACES TO WS-T6-STATUS

           COMPUTE WS-T6-C4 =
                   9000 + 5000
               ON SIZE ERROR
                   MOVE 'SIZE ERROR COMP-4' TO WS-T6-STATUS
           END-COMPUTE

           DISPLAY 'STATUS COMP-4  : ' WS-T6-STATUS

           MOVE SPACES TO WS-T6-STATUS

           COMPUTE WS-T6-C5 =
                   9000 + 5000
               ON SIZE ERROR
                   MOVE 'SIZE ERROR COMP-5' TO WS-T6-STATUS
           END-COMPUTE

           DISPLAY 'STATUS COMP-5  : ' WS-T6-STATUS

           MOVE WS-T6-C4 TO WS-EDIT-UNSIGNED
           DISPLAY 'VALOR COMP-4   : ' WS-EDIT-UNSIGNED

           MOVE WS-T6-C5 TO WS-EDIT-UNSIGNED
           DISPLAY 'VALOR COMP-5   : ' WS-EDIT-UNSIGNED.

5. Por que usamos REDEFINES?

Observe:

01  WS-T1-COMP4.
    05 WS-T1-C4 PIC S9(4) COMP-4.

01  WS-T1-COMP4-RAW REDEFINES WS-T1-COMP4.
    05 WS-T1-C4-BYTES PIC X(2).

O REDEFINES não converte o campo.

Ele apenas permite enxergar os mesmos bytes como uma área alfanumérica.

Depois usamos:

FUNCTION HEX-OF(WS-T1-C4-BYTES)

Isso produz uma apresentação hexadecimal dos bytes.

Para o valor decimal 30000, o hexadecimal é:

7530

Em binário:

0111 0101 0011 0000

Como o bit mais significativo é zero, o número é positivo.


6. O hexadecimal que todo padawan deveria reconhecer

Valor decimal 1

Em halfword:

0001

Valor decimal 100

0064

Valor decimal 1000

03E8

Valor decimal 9999

270F

Valor decimal 14000

36B0

Valor decimal 30000

7530

Valor decimal 32767

7FFF

Valor decimal -1

FFFF

Valor decimal -32768

8000

Valor decimal 60000 sem sinal

EA60

O mesmo padrão EA60, se interpretado como um inteiro de 16 bits com sinal, representa um número negativo:

-5536

Aqui está uma das grandes lições do laboratório:

Os bytes não carregam uma pequena placa dizendo “sou signed” ou “sou unsigned”. A declaração COBOL determina como eles serão interpretados.


7. JCL completo usando a procedure IGYWCL

A IBM fornece procedures catalogadas para compilação e linkedição, embora os nomes, parâmetros e bibliotecas possam variar conforme a instalação.

A procedure IGYWCL normalmente executa duas etapas: compila o programa e depois utiliza o objeto gerado para criar o load module na biblioteca indicada por SYSLMOD. (IBM)

No exemplo abaixo, ajuste:

USER.COBOL
USER.LOAD

para os nomes utilizados em seu ambiente.

//TRUNCLAB JOB (ACCT),'BELLACOSA LAB',
//             CLASS=A,
//             MSGCLASS=H,
//             MSGLEVEL=(1,1),
//             NOTIFY=&SYSUID
//*
//*********************************************************************
//* COMPILACAO 1 - TRUNC(STD)
//*********************************************************************
//CSTD     EXEC IGYWCL,
//         PARM.COBOL='LIB,OBJECT,LIST,MAP,XREF,OFFSET,
//         OPT(2),TRUNC(STD)'
//COBOL.SYSIN DD DISP=SHR,DSN=USER.COBOL(TRUNCLAB)
//COBOL.SYSLIB DD DISP=SHR,DSN=USER.COPYLIB
//LKED.SYSLMOD DD DISP=SHR,DSN=USER.LOAD(TRNSTD)
//*
//*********************************************************************
//* COMPILACAO 2 - TRUNC(OPT)
//*********************************************************************
//COPT     EXEC IGYWCL,
//         PARM.COBOL='LIB,OBJECT,LIST,MAP,XREF,OFFSET,
//         OPT(2),TRUNC(OPT)'
//COBOL.SYSIN DD DISP=SHR,DSN=USER.COBOL(TRUNCLAB)
//COBOL.SYSLIB DD DISP=SHR,DSN=USER.COPYLIB
//LKED.SYSLMOD DD DISP=SHR,DSN=USER.LOAD(TRNOPT)
//*
//*********************************************************************
//* COMPILACAO 3 - TRUNC(BIN)
//*********************************************************************
//CBIN     EXEC IGYWCL,
//         PARM.COBOL='LIB,OBJECT,LIST,MAP,XREF,OFFSET,
//         OPT(2),TRUNC(BIN)'
//COBOL.SYSIN DD DISP=SHR,DSN=USER.COBOL(TRUNCLAB)
//COBOL.SYSLIB DD DISP=SHR,DSN=USER.COPYLIB
//LKED.SYSLMOD DD DISP=SHR,DSN=USER.LOAD(TRNBIN)
//*
//*********************************************************************
//* EXECUCAO DO MODULO TRUNC(STD)
//*********************************************************************
//RUNSTD   EXEC PGM=TRNSTD,
//         COND=(4,LT)
//STEPLIB  DD DISP=SHR,DSN=USER.LOAD
//SYSOUT   DD SYSOUT=*
//CEEDUMP  DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//*
//*********************************************************************
//* EXECUCAO DO MODULO TRUNC(OPT)
//*********************************************************************
//RUNOPT   EXEC PGM=TRNOPT,
//         COND=(4,LT)
//STEPLIB  DD DISP=SHR,DSN=USER.LOAD
//SYSOUT   DD SYSOUT=*
//CEEDUMP  DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//*
//*********************************************************************
//* EXECUCAO DO MODULO TRUNC(BIN)
//*********************************************************************
//RUNBIN   EXEC PGM=TRNBIN,
//         COND=(4,LT)
//STEPLIB  DD DISP=SHR,DSN=USER.LOAD
//SYSOUT   DD SYSOUT=*
//CEEDUMP  DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//

Atenção ao PARM

Algumas procedures aceitam:

PARM.COBOL='...'

Outras instalações utilizam parâmetros diferentes ou possuem uma procedure corporativa própria, como:

COBCL
COBOLCL
IGYWCLG
COB6CL

O esqueleto conceitual permanece:

  1. executar o compilador IGYCRCTL;

  2. gerar o objeto em SYSLIN;

  3. executar o binder;

  4. gravar o load module em SYSLMOD;

  5. executar o programa usando STEPLIB.

A IBM documenta IGYCRCTL como o programa compilador e mostra SYSPRINT, SYSLIN, SYSIN e os arquivos SYSUT entre os DDs principais da compilação. (IBM)


8. Versão do JCL sem COPYLIB

Caso o programa não use nenhum COPY, a linha abaixo poderá ser retirada:

//COBOL.SYSLIB DD DISP=SHR,DSN=USER.COPYLIB

Ela foi incluída porque todo laboratório COBOL sério deve estar preparado para o momento em que alguém acrescentará um copybook de 8.000 linhas chamado:

CPYCOMUM

No qual existirão 147 campos, 23 níveis 88 e um comentário de 1996 dizendo:

* NAO ALTERAR - PROVISORIO

9. O comportamento de TRUNC(STD)

TRUNC(STD) aplica-se aos campos receptores BINARY, COMP e COMP-4 em operações como MOVE e expressões aritméticas.

O resultado é ajustado para o número de dígitos declarado no PICTURE do receptor. (IBM)

Considere:

05 WS-DESTINO PIC 9(4) COMP-4.

E:

MOVE 60000 TO WS-DESTINO

O campo físico possui 2 bytes e poderia comportar 60000 sem sinal.

Entretanto, PIC 9(4) descreve apenas quatro dígitos.

Sob TRUNC(STD), a intenção é corrigir o resultado para essa precisão decimal.

Conceitualmente:

60000

será limitado aos quatro dígitos de baixa ordem:

0000

Outro exemplo:

12345

poderá resultar em:

2345

Por que “poderá”?

Porque é necessário considerar exatamente:

  • a declaração do emissor;

  • a declaração do receptor;

  • se o campo é signed ou unsigned;

  • se a operação é MOVE, ADD, COMPUTE ou outra;

  • se existem intermediários;

  • se há otimizações;

  • se foi usado ON SIZE ERROR;

  • a versão do compilador.

Nos casos documentados pela IBM, entretanto, TRUNC(STD) possui comportamento definido de correção à precisão decimal do PICTURE.


10. O comportamento de TRUNC(OPT)

TRUNC(OPT) é uma opção de desempenho.

O compilador assume que os valores enviados aos campos binários obedecem ao PICTURE.

A partir dessa premissa, ele escolhe a sequência de código mais eficiente. Essa sequência poderá corrigir o resultado para os dígitos do PICTURE ou apenas para o tamanho físico de 2, 4 ou 8 bytes. (IBM)

Por isso, não existe uma resposta universal para isto:

05 WS-DESTINO PIC 9(4) COMP-4.

MOVE 60000 TO WS-DESTINO

quando compilado com:

TRUNC(OPT)

O programa está violando a premissa da opção.

60000 não cabe na precisão de PIC 9(4).

A própria IBM afirma que, nessas condições, o resultado pode ser imprevisível e depender da sequência específica de código gerada. (IBM)

Imprevisível aqui não significa que o processador invocará um demônio.

Significa que o programador não deve escrever uma regra funcional contando com determinado resultado.

Uma mudança aparentemente inocente poderá alterar o código gerado:

MOVE WS-ORIGEM TO WS-DESTINO

pode não produzir a mesma sequência interna que:

COMPUTE WS-DESTINO = WS-ORIGEM

Ou:

ADD ZERO TO WS-ORIGEM
    GIVING WS-DESTINO

O compilador otimiza cada construção.


11. O comportamento de TRUNC(BIN)

Com TRUNC(BIN), todos os campos:

BINARY
COMP
COMP-4

são tratados como se fossem COMP-5.

Os receptores são truncados somente no limite físico de:

2 bytes
4 bytes
8 bytes

O conteúdo binário inteiro do campo torna-se significativo. (IBM)

Considere:

05 WS-DESTINO PIC 9(4) COMP-4.

Sob TRUNC(BIN), o campo é tratado como um inteiro binário nativo de 2 bytes sem sinal.

Assim, poderá conter:

60000

porque 60000 cabe no intervalo físico:

0 a 65535

O PICTURE 9(4) continua escrito no programa, mas a magnitude operacional considerada passa a ser a capacidade física do halfword.


12. COMP-5 nos três programas

Este campo:

05 WS-DESTINO PIC 9(4) COMP-5.

terá comportamento nativo independentemente da compilação usar:

TRUNC(STD)
TRUNC(OPT)
TRUNC(BIN)

A opção TRUNC não afeta itens COMP-5. Eles são tratados como se TRUNC(BIN) estivesse em vigor para aquele campo específico. (IBM)

Por isso, no teste:

MOVE 60000 TO WS-T2-C5

esperamos que o conteúdo binário seja:

EA60

E o valor sem sinal seja:

60000

nos três load modules.


13. Análise do teste clássico de halfword

A IBM utiliza um exemplo semelhante a:

01 BIN-VAR PIC S99 USAGE BINARY.

MOVE 123451 TO BIN-VAR

O receptor ocupa 2 bytes porque possui apenas dois dígitos no PICTURE.

O valor decimal 123451 em hexadecimal de quatro bytes é:

0001E23B

Quando apenas a metade inferior é movida para o halfword, permanecem:

E23B

Como o bit de sinal está ligado, o halfword é interpretado como:

-7621

A IBM documenta os seguintes resultados para esse exemplo:

OpçãoValor resultanteHexadecimal
TRUNC(STD)510033
TRUNC(OPT)-7621E23B
TRUNC(BIN)-7621E23B

Com TRUNC(STD), o valor é corrigido para os dois dígitos do PICTURE, resultando em 51.

Com TRUNC(BIN), são preservados os 16 bits inferiores, resultando em E23B, que representa -7621 em complemento de dois.

Nesse caso específico, TRUNC(OPT) escolhe uma sequência eficiente semelhante ao resultado físico de TRUNC(BIN). (IBM)

Aqui está o coração do laboratório.

O valor não “virou negativo por erro”.

Ele virou negativo porque:

  1. o receptor só comportava 16 bits;

  2. ficaram os 16 bits inferiores de 123451;

  3. o padrão resultante foi E23B;

  4. o campo era assinado;

  5. E23B possui o bit de sinal ligado.

O hardware apenas obedeceu.

Como sempre, a máquina é inocente e o copybook possui bons advogados.


14. Análise do teste clássico de fullword

Outro exemplo documentado pela IBM utiliza:

01 BIN-VAR PIC 9(6) USAGE BINARY.

MOVE 1234567891 TO BIN-VAR

PIC 9(6) ocupa quatro bytes.

O valor 1234567891 também cabe fisicamente nos quatro bytes:

499602D3

Os resultados documentados são:

OpçãoValor
TRUNC(STD)567891
TRUNC(OPT)567891
TRUNC(BIN)1234567891

Com TRUNC(STD), são mantidos os seis dígitos definidos pelo PICTURE.

Com TRUNC(OPT), nesse código específico, o compilador escolhe uma sequência que também produz a correção decimal.

Com TRUNC(BIN), o valor completo permanece porque cabe no fullword. (IBM)

Nosso teste 4 reproduz essa situação.


15. O teste aritmético 9000 + 5000

Temos:

05 WS-T5-C4 PIC 9(4) COMP-4.
05 WS-T5-C5 PIC 9(4) COMP-5.

Inicializamos:

MOVE 9000 TO WS-T5-C4
MOVE 9000 TO WS-T5-C5

Depois:

ADD 5000 TO WS-T5-C4
ADD 5000 TO WS-T5-C5

O resultado matemático é:

14000

Hexadecimal:

36B0

14000 cabe fisicamente em 2 bytes sem sinal.

Mas não cabe em PIC 9(4) segundo sua precisão decimal.

Resultado conceitual com TRUNC(STD)

O COMP-4 deverá ser corrigido para quatro dígitos:

4000

Hexadecimal:

0FA0

O COMP-5 poderá manter:

14000

Hexadecimal:

36B0

Resultado com TRUNC(BIN)

Tanto o COMP-4 quanto o COMP-5 deverão usar a capacidade física:

14000

Resultado com TRUNC(OPT)

Não construa uma regra funcional sobre esse teste.

Como os operandos produzem valor superior ao PICTURE, a premissa de TRUNC(OPT) foi violada.

O resultado deverá ser observado no listing e no SYSOUT da versão específica do compilador.

Essa incerteza é deliberada.

É justamente o que o laboratório pretende ensinar.


16. ON SIZE ERROR: a armadilha dentro da armadilha

Observe:

COMPUTE WS-T6-C5 =
        9000 + 5000
    ON SIZE ERROR
        MOVE 'SIZE ERROR COMP-5'
          TO WS-T6-STATUS
END-COMPUTE

O campo WS-T6-C5 é:

PIC 9(4) COMP-5

Fisicamente, ele poderia armazenar 14000.

Porém, existe uma particularidade importante.

Quando ON SIZE ERROR é utilizado em uma operação aritmética cujo receptor é COMP-5, o limite considerado para a condição de tamanho é o valor indicado pelo PICTURE, e não necessariamente toda a capacidade física do recipiente. A IBM documenta explicitamente essa regra. (IBM)

Assim, embora 14000 caiba em dois bytes, ele excede:

PIC 9(4)

Logo, ON SIZE ERROR poderá ser acionado.

Esta é uma das curiosidades mais traiçoeiras de COMP-5.

Sem ON SIZE ERROR:

ADD 5000 TO WS-T5-C5

o recipiente nativo poderá guardar 14000.

Com ON SIZE ERROR:

COMPUTE WS-T6-C5 = 9000 + 5000
    ON SIZE ERROR

o compilador considera a capacidade decimal descrita.

O padawan pergunta:

— Então o campo comporta 14000 ou não comporta?

A resposta mainframe é:

— Fisicamente, sim. Semanticamente, depende da instrução.

E é por isso que COBOL continua empregando analistas experientes.


17. Como analisar o listing de compilação

Depois de compilar, abra o SYSPRINT.

Procure pela seção de opções.

Você deverá encontrar algo semelhante a:

TRUNC=STD

ou:

TRUNC=OPT

ou:

TRUNC=BIN

Nunca confie apenas no JCL submetido.

Uma procedure corporativa pode:

  • acrescentar opções;

  • substituir opções;

  • usar defaults da instalação;

  • carregar parâmetros de outro membro;

  • invocar preprocessadores;

  • alterar a ordem de precedência.

O listing é a evidência final da compilação.

Procure também:

OPTIMIZE
ARCH
TUNE
NUMCHECK
SSRANGE
ARITH
NUMPROC

Essas opções não substituem TRUNC, mas podem ajudar a explicar diferenças de código gerado, diagnóstico e desempenho.


18. Como comparar os três SYSOUTs

Crie uma tabela manual:

TesteTRUNC(STD)TRUNC(OPT)TRUNC(BIN)
S9(4) COMP-4 = 30000AnotarAnotarAnotar
S9(4) COMP-5 = 30000300003000030000
9(4) COMP-4 = 60000AnotarAnotar60000
9(4) COMP-5 = 60000600006000060000
S99 COMP-4 = 12345151-7621*-7621
S99 COMP-5 = 123451-7621-7621-7621
9(6) COMP-4 = 1234567891567891567891*1234567891
9(6) COMP-5 = 1234567891123456789112345678911234567891

O asterisco indica resultados documentados para a sequência específica apresentada pela IBM. TRUNC(OPT) não deve ser tratado como promessa quando o valor não respeita o PICTURE.

A ideia é preencher a tabela com o resultado real de seu ambiente.


19. Exercício 1 — Descubra o tamanho

Sem executar o programa, determine o tamanho dos campos:

05 CAMPO-A PIC S9(3) COMP-4.
05 CAMPO-B PIC S9(4) COMP-5.
05 CAMPO-C PIC S9(5) COMP-4.
05 CAMPO-D PIC 9(9) COMP-5.
05 CAMPO-E PIC S9(10) COMP-4.
05 CAMPO-F PIC 9(18) COMP-5.

Resposta

CAMPO-A = 2 bytes
CAMPO-B = 2 bytes
CAMPO-C = 4 bytes
CAMPO-D = 4 bytes
CAMPO-E = 8 bytes
CAMPO-F = 8 bytes

20. Exercício 2 — Limite decimal ou limite físico?

Considere:

05 WS-NUMERO PIC 9(4) COMP-5.

Responda:

  1. Qual é o máximo sugerido pelo PICTURE?

  2. Qual é o máximo físico do campo?

  3. O valor 50000 cabe fisicamente?

  4. O valor 70000 cabe fisicamente?

Resposta

1. 9999
2. 65535
3. Sim
4. Não

70000 exigiria mais do que os 16 bits disponíveis.

Se armazenado sem diagnóstico adequado, ocorrerá perda de bits ou condição de tamanho, dependendo da operação.


21. Exercício 3 — Signed contra unsigned

Considere os bytes:

EA60

Interprete-os como:

PIC 9(4) COMP-5

e depois como:

PIC S9(4) COMP-5

Resposta

Sem sinal:

60000

Com sinal:

-5536

A diferença não está nos bytes.

A diferença está na interpretação.


22. Exercício 4 — Preveja o hexadecimal

Preencha:

DecimalHexadecimal de 2 bytes
1?
255?
256?
1000?
9999?
32767?
-1?

Resposta

DecimalHexadecimal
10001
25500FF
2560100
100003E8
9999270F
327677FFF
-1FFFF

23. Exercício 5 — Faça o programa falhar de maneira educativa

Acrescente:

01 WS-PEQUENO PIC S9(4) COMP-5 VALUE ZERO.

Depois execute:

COMPUTE WS-PEQUENO = 32767 + 1
    ON SIZE ERROR
       DISPLAY 'SIZE ERROR DETECTADO'
END-COMPUTE

Perguntas:

  1. 32768 cabe em um halfword com sinal?

  2. Qual seria o padrão hexadecimal de -32768?

  3. Por que o bit de sinal é importante?

Respostas

  1. Não. O máximo positivo é 32767.

  2. 8000.

  3. Em um campo com sinal, o bit mais significativo participa da representação do sinal. Ao ultrapassar 7FFF, o padrão seguinte é 8000, interpretado como -32768.


24. Exercício 6 — Troque COMP-4 por COMP-5

Pegue:

05 WS-CONTADOR PIC 9(4) COMP-4.

Altere para:

05 WS-CONTADOR PIC 9(4) COMP-5.

Execute com os valores:

9998
9999
10000
32767
32768
60000
65535
65536

Observe:

  • decimal exibido;

  • hexadecimal;

  • comportamento com ON SIZE ERROR;

  • comportamento sem ON SIZE ERROR;

  • diferença entre compiladores;

  • diferença entre operações MOVE, ADD e COMPUTE.

Este exercício mostra que trocar apenas o USAGE pode alterar o contrato do campo, mesmo que seu tamanho físico permaneça idêntico.


25. Exercício 7 — O campo corrompido pela interface

Simule um programa externo preenchendo bytes diretamente:

01 WS-AREA.
   05 WS-BIN PIC S9(4) COMP-4.

01 WS-AREA-RAW REDEFINES WS-AREA.
   05 WS-RAW PIC X(2).

Depois:

MOVE X'7530' TO WS-RAW

7530 representa:

30000

Agora exiba WS-BIN nos três programas.

Pergunte:

  • TRUNC(STD) alterará os bytes apenas porque o campo foi consultado?

  • DISPLAY utilizará o conteúdo completo?

  • O comportamento muda se fizermos uma operação aritmética?

  • O que acontece se movermos para um campo DISPLAY PIC S9(4)?

  • O que acontece se movermos para PIC S9(5)?

Este teste é valioso porque imita dados colocados por:

  • C;

  • PL/I;

  • Db2;

  • IMS;

  • uma API;

  • um subsystem;

  • uma estrutura compartilhada;

  • um copybook incompatível.

A IBM recomenda TRUNC(BIN) para programas que recebem valores binários definidos por outros produtos quando esses valores podem não respeitar o PICTURE. Alternativamente, pode-se usar COMP-5 apenas nos campos envolvidos na interface. (IBM)


26. Exercício 8 — Encontre o erro de projeto

Analise:

01 LK-PARAMETROS.
   05 LK-BUFFER-LENGTH PIC 9(4) COMP-4.
   05 LK-RETURN-CODE   PIC S9(4) COMP-4.

A interface em C utiliza:

unsigned short buffer_length;
short return_code;

Perguntas:

  1. buffer_length pode chegar a 65535?

  2. PIC 9(4) comunica corretamente essa faixa?

  3. TRUNC(OPT) é seguro caso o programa C envie 60000?

  4. Qual seria uma declaração mais apropriada?

Possível correção

01 LK-PARAMETROS.
   05 LK-BUFFER-LENGTH PIC 9(4) COMP-5.
   05 LK-RETURN-CODE   PIC S9(4) COMP-5.

Melhor ainda, quando a convenção do projeto permitir, documente a faixa:

01 LK-PARAMETROS.
   05 LK-BUFFER-LENGTH PIC 9(5) COMP-5.
   05 LK-RETURN-CODE   PIC S9(5) COMP-5.

Embora aumentar os noves possa alterar o tamanho físico em algumas faixas, a declaração deve ser analisada em conjunto com o tamanho exigido pela interface.

Em interoperabilidade, não basta dizer “é um número”.

É necessário definir:

signed ou unsigned
16, 32 ou 64 bits
big-endian ou little-endian
por valor ou por referência
com ou sem escala decimal
faixa válida
tratamento de overflow

27. NUMCHECK(BIN) como aliado

Em modernizações, a opção NUMCHECK(BIN) pode ajudar a identificar campos binários que contêm valores incompatíveis com o PICTURE.

Ela é especialmente útil quando uma equipe pretende migrar de:

TRUNC(BIN)

para:

TRUNC(OPT)

ou:

TRUNC(STD)

Porém, ela deve ser utilizada conscientemente em testes, porque verificações adicionais podem afetar desempenho.

A documentação da IBM observa que, quando TRUNC(BIN) e NUMCHECK(BIN) são usados juntos, dados fora da precisão decimal podem gerar diagnóstico ou abend, especialmente quando a intenção é posteriormente mudar para TRUNC(STD) ou TRUNC(OPT). (IBM)

Exemplo de compilação para diagnóstico:

PARM.COBOL='LIST,MAP,XREF,TRUNC(BIN),NUMCHECK(BIN)'

Não implemente isso cegamente em produção.

Primeiro execute em ambiente de testes, avalie os diagnósticos e meça o custo.


28. Desempenho: TRUNC(BIN) não é botão de turbo

Pode parecer que TRUNC(BIN) sempre será mais rápido porque utiliza diretamente o tamanho físico.

Mas isso não é uma regra.

Quando todos os campos binários precisam ser tratados como possuindo até 2, 4 ou 8 bytes significativos, o compilador poderá precisar:

  • utilizar intermediários maiores;

  • gerar conversões adicionais;

  • chamar rotinas auxiliares;

  • preservar faixas maiores durante a aritmética.

A IBM mostra que, no Enterprise COBOL 6, TRUNC(OPT) continua sendo uma boa opção geral de desempenho quando os dados realmente obedecem ao PICTURE. Para itens muito grandes, especialmente acima de nove dígitos, TRUNC(BIN) pode exigir processamento adicional. (IBM)

A regra prática é:

Dados obedecem ao PICTURE:
    considere TRUNC(OPT)

Dados externos podem ultrapassar o PICTURE:
    considere COMP-5 nos campos específicos

Programa inteiro depende de binário nativo:
    avalie TRUNC(BIN)

Não escolha uma opção global para corrigir um único campo mal declarado.

Isso seria semelhante a aumentar a pressão de água da cidade porque a torneira da cozinha está entupida.


29. Checklist de investigação de um problema real

Quando encontrar um valor estranho em COMP-4 ou COMP-5, siga esta ordem.

Passo 1 — Veja a declaração

PIC
USAGE
Sinal
V decimal

Passo 2 — Calcule o tamanho físico

2, 4 ou 8 bytes

Passo 3 — Descubra a origem

O valor veio de:

MOVE
ADD
COMPUTE
arquivo
Db2
CICS
IMS
C
PL/I
API
COMMAREA
LINKAGE SECTION
REDEFINES

Passo 4 — Abra o listing

Confirme:

TRUNC(STD)
TRUNC(OPT)
TRUNC(BIN)

Passo 5 — Veja o hexadecimal

Use:

FUNCTION HEX-OF

ou o dump.

Passo 6 — Interprete o sinal

O campo é:

signed
unsigned

Passo 7 — Compare o receptor

O destino consegue representar todo o valor?

Passo 8 — Examine ON SIZE ERROR

A operação usa essa cláusula?

Passo 9 — Reproduza isoladamente

Crie um programa mínimo.

Passo 10 — Não “corrija” antes de entender

Trocar tudo para COMP-5 pode mascarar outro problema:

  • copybook incorreto;

  • interface incompatível;

  • tamanho errado;

  • endianness;

  • campo corrompido;

  • valor funcionalmente inválido.


30. Easter egg: o valor que mudou após a recompilação

Em algum lugar do planeta existe este código:

05 LK-LENGTH PIC 9(4) COMP.

Durante anos, um programa escrito em C colocou nele:

32000

O sistema funcionava.

Ninguém sabia exatamente por quê, mas funcionava, que é a certificação de qualidade mais respeitada em determinados ambientes legados.

Então chegou o projeto de modernização.

O programa foi recompilado com:

TRUNC(STD)

O valor passou a ser tratado de acordo com os quatro dígitos do PICTURE.

A aplicação começou a reservar buffers menores.

Os registros passaram a chegar truncados.

A sala de crise foi aberta.

O gerente perguntou:

— O COBOL 6 está com defeito?

O compilador, representado por seu advogado, respondeu:

— Eu apenas comecei a respeitar o contrato que vocês escreveram.

Depois de quatro horas, alguém alterou:

PIC 9(4) COMP

para:

PIC 9(4) COMP-5

O sistema voltou a funcionar.

O incidente foi encerrado como:

CAUSA RAIZ: COMPORTAMENTO INESPERADO DA PLATAFORMA

Porque escrever:

CAUSA RAIZ: NINGUEM LEU O COPYBOOK

poderia prejudicar o clima organizacional.


31. O que o padawan deve guardar desta prática

TRUNC(STD) prioriza a precisão decimal declarada no PICTURE.

TRUNC(BIN) prioriza a capacidade física de 2, 4 ou 8 bytes.

TRUNC(OPT) prioriza desempenho e pressupõe que o programa respeita o PICTURE.

COMP-5 aplica o comportamento binário nativo ao campo individual, independentemente da opção TRUNC.

REDEFINES não converte: apenas mostra os mesmos bytes por outra janela.

FUNCTION HEX-OF ajuda a enxergar o que realmente está na memória.

ON SIZE ERROR pode considerar o limite decimal do PICTURE, inclusive em determinadas operações com receptores COMP-5.

Valores externos exigem contratos explícitos de tamanho, sinal, ordem dos bytes e faixa.


Conclusão

O verdadeiro laboratório de COMP-4 e COMP-5 não acontece apenas na WORKING-STORAGE.

Ele acontece na fronteira entre três mundos:

O que o PICTURE declara
O que os bytes comportam
O que o compilador decidiu gerar

Em TRUNC(STD), o PICTURE senta-se na cadeira do diretor e exige que os números respeitem a quantidade de dígitos declarada.

Em TRUNC(BIN), o hardware invade a reunião, coloca os 2, 4 ou 8 bytes sobre a mesa e informa que todos os bits serão utilizados.

Em TRUNC(OPT), o compilador olha para o programador e diz:

— Estou assumindo que você sabe o que está fazendo.

Essa talvez seja a frase mais perigosa já pronunciada por uma ferramenta de desenvolvimento.

O programador COBOL padawan precisa aprender a não depender de acidentes históricos. Um programa não deve funcionar porque um determinado compilador gerou, por coincidência, uma sequência favorável.

Ele deve funcionar porque:

  • a declaração corresponde ao dado;

  • a opção de compilação corresponde ao contrato;

  • o tamanho físico é conhecido;

  • a faixa foi testada;

  • a interface foi documentada;

  • os limites foram verificados;

  • o listing foi lido;

  • o hexadecimal foi compreendido.

No mainframe, o número exibido na tela é apenas a superfície.

Nos bastidores existem bits, bytes, sinais, truncamentos, registradores e decisões tomadas pelo compilador em uma sala escura onde nenhum gerente de projeto jamais entrou.

Quando o padawan aprende a enxergar essa camada invisível, COMP-4 e COMP-5 deixam de ser cláusulas misteriosas.

Tornam-se ferramentas precisas.

E, mais importante, deixam de ser o motivo daquela ligação às três da manhã perguntando por que o valor 60000 voltou como 0000, -5536 ou alguma outra manifestação hexadecimal do caos.

O JCL usa nomes genéricos de datasets e uma IGYWCL típica; os parâmetros exatos da procedure devem ser ajustados ao padrão instalado no ambiente z/OS.

☕ Um Café no Bellacosa Mainframe

Viagem ao Fundo do Mar dos Formatos Numéricos COBOL

Uma expedição pelas profundezas de COMP-1, COMP-2, COMP-3, COMP-4 e COMP-5, onde cada byte pode esconder uma criatura binária.

COMP-4 e COMP-5 sem Mistérios Abrir artigo ↗

Descendo aos arquivos do mainframe...