[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
Esse capítulo descreve algumas dicas e truques para depurar programas numéricos que usam a GSL.
A.1 Usando o gdb | ||
A.2 Examinando registros de ponto flutuante | ||
A.3 Tratando excessões em ponto flutuante | ||
A.4 Opções de alerta do GCC para programas numéricos | ||
A.5 Referências e Leituras Adicionais |
[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
Quaisquer erros reportados pela biblioteca são informados para a função
gsl_error
. Executando seus programas dentro do gdb e ajustando um
ponto de paradas nessa função você pode automaticamente capturar quaisquer erros de
biblioteca. Você pode adicionar um ponto de parada para toda seção colocando
break gsl_error
no seu arquivo ‘.gdbinit’ no diretório onde seu programa é iniciado.
Se o ponto de parada capturar um erro então você pode usar um backtrace
(bt
) para ver a árvore de chamada, e os argumentos que possivelmente
causem o erro. Movendo-se para cima na função que faz a chamada você pode
investigar os valores de variáveis naquele ponto. Aqui está um exemplo
do programa fft/test_trap
, que contém a seguinte
linha,
status = gsl_fft_complex_wavetable_alloc (0, &complex_wavetable);
A função gsl_fft_complex_wavetable_alloc
toma o comprimento de
um FFT como seu primeiro argumento. Quando essa linha é executada um erro irá
ser gerado pelo fato de o comprimento de um FFT ter de ser diferente de zero.
Para depurar esse problema iniciamos o gdb gdb
, usando o arquivo
‘.gdbinit’ para definir o ponto de parada em gsl_error
,
$ gdb test_trap GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i586-debian-linux), Copyright 1996 Free Software Foundation, Inc. Breakpoint 1 at 0x8050b1e: file error.c, line 14.
Quando executamos o programa esse ponto de parada captura o erro e mostra a razão desse referido erro.
(gdb) run Starting program: test_trap Breakpoint 1, gsl_error (reason=0x8052b0d "length n must be positive integer", file=0x8052b04 "c_init.c", line=108, gsl_errno=1) at error.c:14 14 if (gsl_error_handler)
O primeiro argumento de gsl_error
é sempre uma sequência de caracteres descrevendo o
erro. Agora podemos olhar no backtrace para ver o que causou o problema,
(gdb) bt #0 gsl_error (reason=0x8052b0d "length n must be positive integer", file=0x8052b04 "c_init.c", line=108, gsl_errno=1) at error.c:14 #1 0x8049376 in gsl_fft_complex_wavetable_alloc (n=0, wavetable=0xbffff778) at c_init.c:108 #2 0x8048a00 in main (argc=1, argv=0xbffff9bc) at test_trap.c:94 #3 0x80488be in ___crt_dummy__ ()
Podemos ver que o erro foi gerado na função
gsl_fft_complex_wavetable_alloc
quando foi chamada com um
argumento n=0. A chamada original veio da linha 94 no
arquivo ‘test_trap.c’.
Movendo-se para um nível acima da chamada original encontramos a linha que causou o erro,
(gdb) up #1 0x8049376 in gsl_fft_complex_wavetable_alloc (n=0, wavetable=0xbffff778) at c_init.c:108 108 GSL_ERROR ("length n must be positive integer", GSL_EDOM); (gdb) up #2 0x8048a00 in main (argc=1, argv=0xbffff9bc) at test_trap.c:94 94 status = gsl_fft_complex_wavetable_alloc (0, &complex_wavetable);
Dessa forma encontramos a linha que causou o problema. A partir desse ponto
podemos também mostrar os valores de outras variáveis tais como
complex_wavetable
.
[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
O conteúdo de registros de ponto flutuantes podem ser examinados usando o
comando info float
(nas plataformas suportadas).
(gdb) info float st0: 0xc4018b895aa17a945000 Valid Normal -7.838871e+308 st1: 0x3ff9ea3f50e4d7275000 Valid Normal 0.0285946 st2: 0x3fe790c64ce27dad4800 Valid Normal 6.7415931e-08 st3: 0x3ffaa3ef0df6607d7800 Spec Normal 0.0400229 st4: 0x3c028000000000000000 Valid Normal 4.4501477e-308 st5: 0x3ffef5412c22219d9000 Zero Normal 0.9580257 st6: 0x3fff8000000000000000 Valid Normal 1 st7: 0xc4028b65a1f6d243c800 Valid Normal -1.566206e+309 fctrl: 0x0272 53 bit; NEAR; mask DENOR UNDER LOS; fstat: 0xb9ba flags 0001; top 7; excep DENOR OVERF UNDER LOS ftag: 0x3fff fip: 0x08048b5c fcs: 0x051a0023 fopoff: 0x08086820 fopsel: 0x002b
Registros individuais podem ser examinados usando as variáveis $reg, onde reg é o nome do registro.
(gdb) p $st1 $1 = 0.02859464454261210347719
[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
É possível parar o programa sempre que um SIGFPE
de excessão
em ponto flutuante ocorrer. Isso pode ser útil para encontrar a causa de um
infinito inesperado ou de um NaN
. As atuais configurações do controlador podem ser
mostradas com o comando info signal SIGFPE
.
(gdb) info signal SIGFPE Signal Stop Print Pass to program Description SIGFPE Yes Yes Yes Arithmetic exception
A menos que o programa use um controlador de sinal a configuração padrão pode ser
mudada de forma que SIGFPE não seja informado ao programa, uma vez que pode causar
o encerramento do mesmo. O comando handle SIGFPE stop nopass
evita isso.
(gdb) handle SIGFPE stop nopass Signal Stop Print Pass to program Description SIGFPE Yes Yes No Arithmetic exception
Dependendo da plataforma pode ser necessário instruir o kernel para
gerar sinais para excessões em ponto flutuante. Para programas usando GSL
isso pode ser alcançado usando a variável de ambiente GSL_IEEE_MODE
juntamente com a função gsl_ieee_env_setup
como descrito
em veja seção Aritmética em Ponto Flutuante IEEE.
(gdb) set env GSL_IEEE_MODE=double-precision
[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
Escrevendo programas numéricos confiáveis em C requer grande cuidado. O as seguintes opções de alerta do GCC são recomendadas quando compilando programas numéricos:
gcc -ansi -pedantic -Werror -Wall -W -Wmissing-prototypes -Wstrict-prototypes -Wconversion -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wnested-externs -fshort-enums -fno-common -Dinline= -g -O2
Para detalhes sobre cada opção consulte o manual Using and Porting GCC. A seguinte tabela fornece uma breve explanação de quais tipos de erro essas opções capturam.
-ansi -pedantic
Usando ANSI C, e rejeitando quaisquer extensões não ANSI. Esses sinalizadores ajudam na escrita de programas portáveis que irão compilar nos outros sistemas.
-Werror
considera alertas como sendo erros, de forma que a compilação pare. Isso evita alertas rolando para o topo da tela e sendo perdidos. Você não estará apto a compilar o programa até estar completamente livre de alertas.
-Wall
Habilita um conjunto de alertas para problemas comuns de programação. Você
precisa -Wall
, mas isso não é suficiente por si só.
-O2
Habilita otimização. Os alertas por variáveis não inicializadas em
-Wall
garantem que o otimizador analize o código. Se não houver
otimizações então esses alertas não são gerados.
-W
Habilita alertas extras não inclídos em -Wall
, tais como
valores de retorno omitidos e comparações entre inteiros sinalizados e inteiros
não sinalizados.
-Wmissing-prototypes -Wstrict-prototypes
Alerta se houver qualquer protótipo inconsistente ou omitido. Sem protótipos é mais difícil detectar problemas com argumentos incorretos.
-Wconversion
O principal uso dessa opção é alertar sobre conversões de inteiro sinalizado para
inteiro não sinalizado. Por exemplo, unsigned int x = -1
. Se você precisa
executar tal conversão você pode usar uma conversão expçícita.
-Wshadow
Alerta sempre que uma variável local oculta outra variável local. Se duas variáveis possuem o mesmo nome então é uma potencial fonte de confusão.
-Wpointer-arith -Wcast-qual -Wcast-align
Essas opções alertam se você tentar fazer aritmética de apontadores para tipos que
não possuem um tamanho, tais como void
, se você remove coverção de
const
a partir de um apontador, ou se você converte um apontador para um tipo que tem um
tamanho diferente, causando um alinhamento inválido.
-Wwrite-strings
Essa opção fornece a constantes do tipo string um qualificador const
de forma que
irá ser um erro em tempo de compilação tentar sobrescrevê-la.
-fshort-enums
Essa opção torna o tipo de enum
tão curto quanto possível. Normalmente
isso torna um enum
diferente a partir de um int
. Consequentemente quaisquer
tentativas de atribuir um apontador a um inteiro para um apontador para um enum irá gerar um
alerta de alinhamento de conversão.
-fno-common
Essa opção evita que variáveis globais serjam simultâneamente definidas em
diferentes arquivos objetos (você recebe um erro na hora da linkagem). Tal como uma variável
deve ser definida em um arquivo e referenciada em outro arquivo com uma
declaração extern
.
-Wnested-externs
Alerta se uma declaração extern
for encontrada dentro de uma
função.
-Dinline=
A palavra chave inline
não é parte do ANSI C. Dessa forma se você deseja usar
-ansi
com um programa que usa funções inline você pode usar essa
definição de préprocessador para remover as palavras chave inline
.
-g
Sempre faz sentido colocar símbolos de depuração no executável de forma que
você possa depurá-lo usando o gdb
. O único efeito de símbolos de depuração
é aumentar o tamanho do arquivo, e você pode usar o comando
strip
para removêlos mais tarde se necessário.
[ << ] | [ < ] | [ Acima ] | [ > ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
Os seguintes livros são leituras essenciais para qualquer um que escreve e depura programas numéricos com o GCC e com o GDB.
Para um tutorial de introdução ao compilador C GNU e programas relacionados, veja
[ << ] | [ >> ] | [Topo] | [Conteúdo] | [Índice] | [ ? ] |
Esse documento foi gerado em 23 de Julho de 2013 usando texi2html 5.0.