none
数値を直接指定した場合に、DivideByZeroExceptionがtrapできません RRS feed

  • 質問

  • いつもお世話になっております。

    0除算の例外をtrapしようとtrap構文を利用してみたのですが、
    思ったように動作する場合と、動作しない場合があり、原因が掴めない状態です。

    ■上手く動作する場合

    $i = 0
    
    Trap [DivideByZeroException] {
      "Divide By Zero"; break
    }
    
    1 / $i
    

    ■上手く動作しない場合(変数$iを利用するのではなく、直接0を指定しました)

    Trap [DivideByZeroException] {
      "Divide By Zero"; break
    }
    
    1 / 0
    

    ちなみに、上の式の方で、$i = 1として$i / 0としても問題なく動作しましたので、
    「0が原因で~~」というよりは「変数を使っているかどうか」のように見えます。
    また、DivedeByZeroExceptionをExceptionに置き換えても同じ動作になりましたので、「別の例外として扱う」ということも無いようです。

    数値を直接指定した場合と変数を割り当てて指定した場合で、例外処理に違いがあるのでしょうか?
    もしくは、他に原因があるのでしょうか?

    どなたか、アドバイスをよろしくお願いいたします。

    2010年9月6日 4:54

回答

  • どうも、数値で直接書いた場合は、実行する前にパーサーがエラーを吐いているようですね。
    実行前にパーサーが計算して返そうとするみたいです。

    たとえば、以下のようにしてみてください

    Write-Output "Test"
    1/[int]0
    

    Testと表示されることから、実行されていることが分かります。

    では、次に、以下のようにしてみてください。

    Write-Output "Test"
    1/0
    
    
    

    今度はTestと表示され無かったと思います。このことから、どうも実行前のパーサーが、先に計算してしまってその時点で例外を出しているみたいです。なので、RuntimeなExceptionでは拾えないようです。
    #ごめんなさい、根拠となる文章を見つけることができませんでしたm(_ _)m

    WikiPediaに以下の一文がありました。算術式がコマンドラインに入力されたらすぐ評価される、とあるのがそれなのかもしれませんが何を根拠に書いているのか不明でした。
    抜粋:
    The PowerShell scripting language also evaluates arithmetic expressions entered on the command line immediately, and it parses common abbreviations, such as GB, MB, and KB.
    http://en.wikipedia.org/wiki/Windows_PowerShell

    2010年9月6日 11:48

すべての返信

  • どうも、数値で直接書いた場合は、実行する前にパーサーがエラーを吐いているようですね。
    実行前にパーサーが計算して返そうとするみたいです。

    たとえば、以下のようにしてみてください

    Write-Output "Test"
    1/[int]0
    

    Testと表示されることから、実行されていることが分かります。

    では、次に、以下のようにしてみてください。

    Write-Output "Test"
    1/0
    
    
    

    今度はTestと表示され無かったと思います。このことから、どうも実行前のパーサーが、先に計算してしまってその時点で例外を出しているみたいです。なので、RuntimeなExceptionでは拾えないようです。
    #ごめんなさい、根拠となる文章を見つけることができませんでしたm(_ _)m

    WikiPediaに以下の一文がありました。算術式がコマンドラインに入力されたらすぐ評価される、とあるのがそれなのかもしれませんが何を根拠に書いているのか不明でした。
    抜粋:
    The PowerShell scripting language also evaluates arithmetic expressions entered on the command line immediately, and it parses common abbreviations, such as GB, MB, and KB.
    http://en.wikipedia.org/wiki/Windows_PowerShell

    2010年9月6日 11:48
  • 自分でももうちょっと調べてみました。

    動作する方をtest1.ps1として、動作しない方をtest2.ps1として、それぞれSet-PSDebug -Stepにて確認してみました。

    すると動作する方は、

    1+  <<<< .\test1.ps1
    デバッグ:    1+  <<<< .\test1.ps1
    デバッグ:     ! CALL function 'test1.ps1'  (defined in file 'C:\work\test1.ps1')

    動作しない方は

    1+  <<<< .\test2.ps1
    デバッグ:    1+  <<<< .\test2.ps1

    ということでCALL functionすらしていないみたいです。

    動作していない方で調べてみると、
    $_.FullQueryErrorId
    RuntimeException

    $_.Exception.ToString()
    System.Management.Automation.RuntimeException: 0 で除算しようとしました。 ---> System.DivideByZeroException: 0 で除算しようとしました。
       場所 System.Management.Automation.ParserOps.PolyDiv(ExecutionContext context, Token opToken, Object lval, Object rval)

    みたいな記述があるので、1/0という計算に対してDivideByZeroException自体はCatch(Trap)しているみたいです。

    動作している方にあるような CALL functionが来る前にExceptionを吐いてしまっているので、スクリプト内のtrap文を実行する前(というよりスクリプト実行前)に
    例外処理が起こっている(みたいに見えます)。

    なので、Chukiさんに教えていただいた
    >どうも実行前のパーサーが、先に計算してしまってその時点で例外を出しているみたいです。
    という説明が、根拠となる文章は見つからないとのことではありますが正しいのではないかと感じました。

    Chukiさん、勉強になりました。ありがとうございました。

    2010年9月6日 14:23