| 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)eTRUNC(BIN);executaremos três load modules diferentes;
mostraremos o conteúdo decimal e hexadecimal dos campos;
compararemos
COMP-4comCOMP-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ígitos | Armazenamento |
|---|---|
| 1 a 4 | 2 bytes |
| 5 a 9 | 4 bytes |
| 10 a 18 | 8 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:
executar o compilador
IGYCRCTL;gerar o objeto em
SYSLIN;executar o binder;
gravar o load module em
SYSLMOD;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,COMPUTEou 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ção | Valor resultante | Hexadecimal |
|---|---|---|
TRUNC(STD) | 51 | 0033 |
TRUNC(OPT) | -7621 | E23B |
TRUNC(BIN) | -7621 | E23B |
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:
o receptor só comportava 16 bits;
ficaram os 16 bits inferiores de
123451;o padrão resultante foi
E23B;o campo era assinado;
E23Bpossui 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ção | Valor |
|---|---|
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:
| Teste | TRUNC(STD) | TRUNC(OPT) | TRUNC(BIN) |
|---|---|---|---|
S9(4) COMP-4 = 30000 | Anotar | Anotar | Anotar |
S9(4) COMP-5 = 30000 | 30000 | 30000 | 30000 |
9(4) COMP-4 = 60000 | Anotar | Anotar | 60000 |
9(4) COMP-5 = 60000 | 60000 | 60000 | 60000 |
S99 COMP-4 = 123451 | 51 | -7621* | -7621 |
S99 COMP-5 = 123451 | -7621 | -7621 | -7621 |
9(6) COMP-4 = 1234567891 | 567891 | 567891* | 1234567891 |
9(6) COMP-5 = 1234567891 | 1234567891 | 1234567891 | 1234567891 |
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:
Qual é o máximo sugerido pelo
PICTURE?Qual é o máximo físico do campo?
O valor
50000cabe fisicamente?O valor
70000cabe 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:
| Decimal | Hexadecimal de 2 bytes |
|---|---|
| 1 | ? |
| 255 | ? |
| 256 | ? |
| 1000 | ? |
| 9999 | ? |
| 32767 | ? |
| -1 | ? |
Resposta
| Decimal | Hexadecimal |
|---|---|
| 1 | 0001 |
| 255 | 00FF |
| 256 | 0100 |
| 1000 | 03E8 |
| 9999 | 270F |
| 32767 | 7FFF |
| -1 | FFFF |
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:
32768cabe em um halfword com sinal?Qual seria o padrão hexadecimal de
-32768?Por que o bit de sinal é importante?
Respostas
Não. O máximo positivo é
32767.8000.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,ADDeCOMPUTE.
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?DISPLAYutilizará 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:
buffer_lengthpode chegar a65535?PIC 9(4)comunica corretamente essa faixa?TRUNC(OPT)é seguro caso o programa C envie60000?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.
Descendo aos arquivos do mainframe...