C ++ / CLI: SIGFPE, _control87, _fpreset, Portierung der alten nicht verwalteten Watcom C-Anwendung auf .NET

9

Ich habe eine mehrere tausend Zeilen umfassende Anwendung, die auf SIGFPE angewiesen ist (behandelt durch einen Funktionszeiger, der an signal () übergeben wird), um den Zustand zu ändern und den Code korrekt laufen zu lassen, wenn bestimmte Gleitkommazustände auftreten. Unter C ++ / CLI im verwalteten Modus generiert _control87 jedoch eine System.ArithmeticException, die in einer statischen Bibliothek ausgeführt wird, die in C geschrieben ist. _fpreset und _control87 werden nicht unterstützt.

Wie bekomme ich klassischen, nicht verwalteten SIGFPE-Vorgang in einer C ++ / CLI-Anwendung arbeiten? Die Anzahl der Orte, an denen Gleitkommazahlen in meiner Anwendung vorkommen, könnte immens sein und ich verstehe nicht alle numerischen Methoden, die vor Jahren von anderen Programmierern geschrieben wurden.

Ich möchte, dass die Old-School-Exception-Behandlung an einer Gleitkommadivision mit Null arbeitet, nicht an einem INF-Wert. Platform invoke style funktioniert nicht, und #pragma managed (off) macht auch keinen Trick.

Welche Möglichkeiten habe ich?

    
user343400 26.07.2010, 20:01
quelle

1 Antwort

4

Hier gibt es einige sehr ernste Probleme. Das Aktivieren von Gleitkommaausnahmen ist grob mit der Ausführung von verwaltetem Code nicht kompatibel. Bis auf die Grundlagen können Sie den JIT-Compiler problemlos zum Absturz bringen. Mit welchem ​​Problem kämpfen Sie, wenn Sie _control87 () verwenden.

Und ja, Sie erhalten eine CLR-Ausnahme, es setzt eine Ausnahmebackstop, wenn es nativen Code ausführt. Ein Signal-Handler wird nur dann aufgerufen, wenn eine Ausnahme ausgelöst wird und es keinen Code gibt, um damit umzugehen. Unvermeidlicherweise sieht die CLR die Ausnahme, bevor die C-Laufzeitbibliothek sie sehen kann. So erhalten Sie den SIGFPE-Handler-Aufruf nie.

Der einzige vernünftige Weg, um dies zu tun, ist einen Wrapper schreiben, der die Ausnahme vor der CLR abfangen kann. Außerdem ist es sehr, sehr wichtig, dass Sie das FPU-Steuerwort sorgfältig verwalten. Sie können sich nur erlauben, FPU-Ausnahmen aktiviert zu haben, während der native Code läuft. Dies erfordert eine Reihe von grobkörnigem Code, der davor warnt, dass Sie es nicht sehr genießen werden.

Du hast kein Snippet gepostet, also muss ich ein dummes Beispiel erfinden:

%Vor%

Um fvorgang () aufzurufen, müssen Sie den Exception-Handler innerhalb der C-Laufzeitbibliothek aufrufen. Zum Glück ist es offen gelegt und du kannst es verlinken, du brauchst nur eine Deklaration dafür, damit du es nennen kannst:

%Vor%

Sie müssen sicherstellen, dass es immer nur für Gleitkommaausnahmen aufgerufen wird. Wir brauchen also einen Wrapper, der auf den Ausnahmecode achtet:

%Vor%

Nun können Sie einen Wrapper für badmath () schreiben, der den Signal-Handler aufgerufen bekommt:

%Vor%

Diese wiederum kann von einer C ++ / CLI-Klasse aufgerufen werden, die Sie von einem beliebigen verwalteten Code aus aufrufen können. Es muss sichergestellt werden, dass Gleitkommaausnahmen vor dem Aufruf aktiviert und nach dem Aufruf wieder hergestellt werden:

%Vor%

Beachten Sie den Aufruf von _control87 (), es aktiviert alle schwebenden Ausnahmen außer "ungenaues Ergebnis". Dies ist notwendig, um den Code zu sperren. Wenn du es nicht maskierst, stirbt die CLR einen schrecklichen Tod und wirft immer und immer wieder Ausnahmen, bis der Name der Seite ihr ein Ende setzt. Hoffentlich braucht Ihr Signal-Handler es nicht.

    
Hans Passant 13.06.2015 14:24
quelle