Pergunta

Eu tenho um programa que deliberadamente executa uma divisão por zero (e armazena o resultado em uma variável volátil), a fim de parar em determinadas circunstâncias. No entanto, eu gostaria de ser capaz de desativar esta parada, sem alterar a macro que realiza a divisão por zero.

Existe alguma maneira de ignorá-lo?

Eu tentei usar

#include <signal.h>
...
int main(void) {
  signal(SIGFPE, SIG_IGN);
  ...
}

mas ainda morre com a mensagem "Exceção de ponto flutuante (núcleo)".

Eu não realmente usar o valor, então eu realmente não me importo o que é atribuído à variável; 0, aleatório, indefinido ...

EDIT: Eu sei que isso não é o mais portátil, mas está destinado a um dispositivo embutido que funciona em muitos sistemas operacionais diferentes. A ação parada padrão é dividir por zero; outras plataformas requerem diferentes truques para forçar uma reinicialização induzida cão de guarda (tal como num ciclo infinito com interrupções desativado). Para um ambiente de teste PC (linux), eu queria desativar o impasse sobre a divisão por zero sem depender de coisas como assert.

Foi útil?

Solução

Por que você deliberadamente realizar uma divisão por zero a parada? você não poderia exit(-1) ou algum equivalente?

Especialmente se você não precisa o resultado da divisão por 0, isso simplesmente não faz sentido.

Outras dicas

Ok, em primeiro lugar, você deve estar usando sigaction (2) em vez do signal() obsoleto.

Em segundo lugar, usando SIGFPE para efeito de cessação do programa é absurdo, como você deve estar levantando um sinal de como SIGTERM ou SIGUSR1 vez de gambiarra algum outro sinal para o seu efeito colateral e ignorando seu valor semântico. E mais especificamente, a página man para sigaction (2) tem uma seção NOTAS com uma sinopse sobre SIGFPE que indica uma ou duas maneiras o uso pretendido do que é quebrado.

O que você deve fazer é raise (3) um sinal quando o usuário quiser encerrar. Em seguida, use o campo sa_handler na estrutura sigaction a mudança se deve ignorar (SIG_IGN) ou cancelar (SIG_DFL) sobre esse sinal.

int main(void) {
  struct sigaction my_action;

  my_action.sa_handler = SIG_IGN;
  my_action.sa_flags = SA_RESTART;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1);  /* Ignored */

  my_action.sa_handler = SIG_DFL;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1); /* Terminates */

  return 0;
}

Dito isto, eu não posso ver porque você pode usar sinais em vez de um exit() simples.

Verifique o valor de retorno

signal(SIGFPE, SIG_IGN);

Se você receber SIG_ERR, verifique o valor da errno para descobrir o que deu errado. Isso é tanto quanto você pode fazer portably.

Eu sei que você não quer mudar a divisão por zero, mas é não portável e contra-intuitivo. Você quer coredump se alguma condição ocorre, mas ser capaz de desativar esse comportamento sem editar o código? Use assert e NDEBUG.

Isto não é portátil, mas em x86 pode controlando a FPU:

Usando gcc no Linux (eu tenho certeza que outros compiladores têm instalações semelhantes):

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

Como os padrões _FPU_DEFAULT para definir _FPU_MASK_ZM (ZM significa Zero-Divide-Mask).

void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);

Você poderia fazer com que o programa para sair através de uma expressão menos artificial? Por exemplo:

#include <signal.h>

#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif

Eu ficaria hesitante para substituir o comportamento padrão, para que alguma outra parte de sua divisão por zero programa involuntariamente. Alternativamente, se você está forçando-o a sair desta forma a fim de obter um dump de memória, você pode querer olhar em usar pontos de interrupção dentro de um depurador. Ou, se você estiver em um sistema com o depurador gdb, o utilitário gcore pode ser útil.

Se você tem controle sobre o código de deixar de funcionar, então eu recomendo também para alterar o código de morrer de alguma outra forma. Se você não fizer isso, você pode tentar instalar um manipulador de sinal vazio em vez (ou seja, o uso signal(SIGFPE, &EmptyFunction)), mas você ainda está confiando em um comportamento indefinido, então não há nenhuma garantia de que vai ainda trabalhar em outros sistemas, ou outro kernel ou C versões da biblioteca.

lnmiit l sobre o código deixando de funcionar, então eu recomendo também para alterar o código de morrer de alguma outra forma. Se você não fizer isso, você pode tentar instalar um

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top