none
VB2010 配列変数をLong指定するとエラーになる RRS feed

  • 質問

  • X64を使っている場合、配列変数をLongにすれば、実行速度が上がると考え

    配列変数をLongにしてみましたが、エラーになってしまいます。

    Longを使えないようにする理由があるのでしょうか?

    Kazuo Turumi

     

     

    2011年3月18日 21:52

回答

  • For i As Long =1 to 9
    For j As Long = 1 to 9
    mSelection.Cells(i,j)= Cstr(mmSelection(i,j))
    Next
    Next

    とすると、「Option Stricy OnでLongからintegerへの暗黙的な変換はできません」となってしまいます。
    これは配列変数にintegerしか使えないということを意味しませんか?

    配列変数とはそういうことですか。(私は Long 型の配列を入れておく変数と解釈していました)
    配列のインデックス、つまり ( ) 内に指定する要素は Integer 型でなければなりません。
    これはそういう仕様に基づいて実装されているため、制限事項です。
    (関数の引数が Integer 型で定義されていると捉えて頂ければ、わかりやすいかと思います)

    推測ですが、カウンタの変数を Long 型にしたところで実行効率に有意の差はないと思われます。
    インクリメント・デクリメントレベルで差ができるようでは、x86 のアプリを動かしたときに実行効率の大きな低下を招きますし。

    また、Long 型の引数を用意しない理由は正確なところを言えませんが、x86 環境で逆に効率が悪くなる恐れ、事実上、64bit の整数型で表さないといけないほどの要素数を扱うことがほとんどないことが推測されます。
    (Integer 型で表せない範囲、2GB を超える配列を扱うことは、それ自体が非効率と言える場面がほとんどです)

    # どうしてもカウンタ変数を Long 型にしたいのであれば、CInt などを使ってキャストをするべきでしょう。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります
    • 回答としてマーク Kazuo Turumi 2011年3月20日 21:10
    2011年3月20日 15:43
    モデレータ

すべての返信

  • どんなエラーか明確にせず、質問されても回答できません。
    エラーや例外でお困りなのであれば、どのようなコードを書いて、どのようなエラーが出たか、例外が出たかを適切に説明してください。

    なお、Long の配列自体は普通に作れます。
    おそらくは、作った後の使い方に問題があるのではないかと思われます。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月19日 6:22
    モデレータ
  • 具体的に条件を示しませんでしたが

    Option Strict Onで、たとえばVSTOで

    For i As Long =1 to 9

     For j As Long = 1 to 9

        mSelection.Cells(i,j)= Cstr(mmSelection(i,j))

     Next

    Next

    とすると、「Option Stricy OnでLongからintegerへの暗黙的な変換はできません」となってしまいます。

    これは配列変数にintegerしか使えないということを意味しませんか?

     


    Kazuo Tsurumi
    2011年3月20日 15:22
  • For i As Long =1 to 9
    For j As Long = 1 to 9
    mSelection.Cells(i,j)= Cstr(mmSelection(i,j))
    Next
    Next

    とすると、「Option Stricy OnでLongからintegerへの暗黙的な変換はできません」となってしまいます。
    これは配列変数にintegerしか使えないということを意味しませんか?

    配列変数とはそういうことですか。(私は Long 型の配列を入れておく変数と解釈していました)
    配列のインデックス、つまり ( ) 内に指定する要素は Integer 型でなければなりません。
    これはそういう仕様に基づいて実装されているため、制限事項です。
    (関数の引数が Integer 型で定義されていると捉えて頂ければ、わかりやすいかと思います)

    推測ですが、カウンタの変数を Long 型にしたところで実行効率に有意の差はないと思われます。
    インクリメント・デクリメントレベルで差ができるようでは、x86 のアプリを動かしたときに実行効率の大きな低下を招きますし。

    また、Long 型の引数を用意しない理由は正確なところを言えませんが、x86 環境で逆に効率が悪くなる恐れ、事実上、64bit の整数型で表さないといけないほどの要素数を扱うことがほとんどないことが推測されます。
    (Integer 型で表せない範囲、2GB を超える配列を扱うことは、それ自体が非効率と言える場面がほとんどです)

    # どうしてもカウンタ変数を Long 型にしたいのであれば、CInt などを使ってキャストをするべきでしょう。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります
    • 回答としてマーク Kazuo Turumi 2011年3月20日 21:10
    2011年3月20日 15:43
    モデレータ
  • 既に解決しているようですが若干補足。

    普通の配列の添字にはlong(64bit)変数を使用できますが、該当の箇所はExcelがActiveX/COM経由で提供している配列であるため、添字の型がinteger(32bit)に限定されています。正確にはCells COMオブジェクトに64bit添字用のインターフェイスが提供されていません。

    2011年3月20日 23:39
  • 普通の配列の添字にはlong(64bit)変数を使用できますが、

    補足・指摘ありがとうございます。
    この部分、確かめずに書いていたので誤った認識を広めてしまったかもしれません。申し訳ありません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月20日 23:52
    モデレータ
  •  「Visual Basic における配列」から、つらつら読んでみましたが、配列の添字の上限については書かれていませんでした。しかし、「UBound 関数 (Visual Basic)」の戻り値が Integer と規定されているので、Integerの範囲を超えた上限を指定すると、この関数が正しい結果を報告しなくなるでしょう。また、Array.Length プロパティも int(Int32)なので、この範囲を超える値を使うのは、止めた方が良いでしょう。ちなみに符号ありです。


    普通の配列の添字にはlong(64bit)変数を使用できますが

     Option Strict Off では使用できますが、Option Strict On では、コード入力時にエラーになります。プロジェクトのプロパティ ページ、「コンパイル」で、「暗黙的な変換」を「エラー」以外にすると、エラーとはなりません。Int64 -> Int32 は縮小変換なので、エラーとするか警告にとどめるか、はたまた素通りするかは、処理系依存でしょうね。ちなみに、C# は素通りです。なので、3000000000L(Int64 で 30億)を与えてみると、OverflowException が発生しました。じゃ、Int32 に代入してから…と思うと、コンパイル エラー発生。配列の添字も検出する、Option Strict On の VB が賢い?

    static void Main(string[] args)
    
    {
    
     Int64 l = 3000000000L;
    
     char[] ary = new char[l]; // ← 30億を32ビットに縮小変換すると負数になるので OverflowException
    
     for (Int64 i = 0L; i < l; ++i) { ary[i] = '\0'; }
    
     Console.WriteLine(ary.Length);
    
    }
    
    
    static void Main(string[] args) { Int64 l = 3000000000L; Int32 i32 = l; // ← ここで「型 'long' を 'int' に暗黙的に変換できません」コンパイル エラー Console.WriteLine(i32); char[] ary = new char[l]; for (Int64 i = 0L; i < l; ++i) { ary[i] = '\0'; } Console.WriteLine(ary.Length); }

    訂正:30億は、Int32 の範囲でした。縮小変換じゃなくて、最上位の符号ビットが立つので、負数です。


    Jitta@わんくま同盟
    2011年3月22日 12:53