Pergunta

Estou trabalhando na portabilidade de um aplicativo Visual C++ para GCC (deve ser compilado em MingW e Linux).

O código existente usa __try { ... } __except(1) { ... } blocos em alguns lugares para que quase nada (a não ser talvez erros do tipo falta de memória?) Faria o programa sair sem fazer algum registro mínimo.

Quais são as opções para fazer algo semelhante com o GCC?

Editar:Obrigado pelo ponteiro para as opções /EH no Visual Studio, o que preciso agora é de alguns exemplos sobre como lidar com sinais no Linux.encontrei esta mensagem de 2002.

Que outros sinais além SIGFPE e SIGSEVG devo tomar cuidado?(Principalmente se preocupa com aqueles que podem ser criados a partir de meu fazendo algo errado)

Informações sobre recompensas:Quero que meu aplicativo seja capaz de registrar automaticamente tantas condições de erro quanto possível antes de sair.

Que sinais posso receber e quais geralmente seriam impossíveis de registrar uma mensagem de erro depois?(Sem memória, o que mais?)

Como posso lidar com exceções e (o mais importante) sinalizar de forma portátil que o código pelo menos funciona da mesma forma no Linux e no MingW.#ifdef está OK.

A razão pela qual não tenho apenas um processo wrapper que registra a falha é que, por motivos de desempenho, economizo a gravação de alguns dados no disco até o último minuto; portanto, se algo der errado, quero fazer todas as tentativas possíveis para gravar os dados antes saindo.

Foi útil?

Solução

try { xxx } catch(...) { xxx } seria mais portátil, mas pode não capturar tanto.Depende das configurações e ambientes do compilador.

Usando as configurações padrão do VC++, erros assíncronos (SEH) não são entregues à infraestrutura C++ EH;para capturá-los, você precisa usar manipuladores SEH (__try/__except).VC++ permite rotear erros SEH por meio do tratamento de erros C++, o que permite que um catch(...) capture erros SEH;isso inclui erros de memória, como desreferências de ponteiro nulo. Detalhes.

No Linux, entretanto, muitos dos erros para os quais o Windows usa SEH são indicados por meio de sinais.Eles nunca são capturados por try/catch;para lidar com eles, você precisa de um manipulador de sinal.

Outras dicas

Por que não usar as exceções padrão C++ em vez da extensão proprietária da MSFT?C++ possui um conceito de tratamento de exceções.

struct my_exception_type : public logic_error {
    my_exception_type(char const* msg) : logic_error(msg) { }
};

try {
    throw my_exception_type("An error occurred");
} catch (my_exception_type& ex) {
    cerr << ex.what << endl;
}

C++ também possui uma cláusula “catchall”, portanto, se você quiser registrar exceções, poderá usar o seguinte wrapper:

try {
    // …
}
catch (...) {
}

No entanto, isso não é muito eficiente em C++ porque a criação de um wrapper geral significa que o código de manipulação deve ser inserido em todo quadro de pilha subsequente pelo compilador (ao contrário de sistemas gerenciados como .NET, onde o tratamento de exceções não tem custo adicional, desde que nenhuma exceção seja realmente lançada).

Para portabilidade, uma coisa a tentar é usar blocos try-catch para a maioria das exceções vanilla e, em seguida, definir um manipulador de término (set_terminate_handler) para ter um gancho mínimo disponível para condições de saída catastróficas.Você também pode tentar adicionar algo como um manipulador atexit ou on_exit.Seu ambiente de execução pode ser bizarro ou corrompido quando você entra nessas funções, é claro, então tome cuidado ao presumir um ambiente sensato.

Finalmente, ao usar pares try-catch regulares, você pode considerar o uso de blocos try de função em vez de abrir um bloco try no corpo de uma função:

int foo(int x) try {
  // body of foo
} catch (...) {
   // be careful what's done here!
}

eles são um pedaço relativamente desconhecido de C++ e podem, em alguns casos, oferecer recuperação mesmo no caso de corrupção parcial (em pequena escala) da pilha.

Finalmente, sim, você provavelmente desejará investigar quais sinais você pode manipular continuamente por conta própria ou quais você pode abortar e, se desejar menos mecanismos de manipulação, considere chamar a versão sem lançamento do novo operador e compilar para não gerar exceções de ponto flutuante, se necessário (você sempre pode verificar isnan(.), isfinite(.), nos resultados do FP para se proteger).

Nessa última nota, tenha cuidado:Percebi que as funções de classificação de resultados de ponto flutuante podem estar em cabeçalhos diferentes no Linux e no Windows ...então você pode ter que condicionar essas inclusões.

Se você estiver com raiva, escreva tudo usando setjmp e longjmp (isso é uma piada...).

Capturando exceções C++ com catch(...) já coloca você em uma zona crepuscular.

Tentando detectar erros não detectados por catch(...) coloca você diretamente dentro de um comportamento indefinido.Nenhum código C++ tem garantia de funcionamento.Seu código de registro mínimo pode fazer com que o míssil seja lançado.

Minha recomendação é nem tentar catch(...).Capture apenas exceções que você possa registrar de forma significativa e segura e deixe o sistema operacional cuidar do resto, se houver.

A depuração post-mortem fica feia se você tiver erros ao lidar com falhas de código além da causa raiz.

Uma maneira fácil de usar, portátil e que quase não utiliza recursos seria capturar classes vazias.Eu sei que isso pode parecer estranho no início, mas pode ser muito útil.

Aqui está um exemplo que fiz para outra pergunta que também se aplica à sua: link

Além disso, você pode ter mais de 1 captura:

try
{
   /* code that may throw exceptions */
}
catch (Error1 e1)
{
   /* code if Error1 is thrown */
}
catch (Error2 e2)
{
   /* code if Error2 is thrown */
}
catch (...)
{
   /* any exception that was not expected will be caught here */
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top