Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

ビット演算 解決済み

タグの編集...

投稿者 mick   (学生)   投稿日時 2014/8/17 16:06:59
C#はある程度わかるのですが、VBのほうがいまいち深く理解できていないので
言語をより深く理解するためC#とVB.Net両方を改めて勉強中です。

C#のコード
byte B = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte G = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte R = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte A = Marshal.ReadByte(bitmapData.Scan0, offset++);
int rgba = R | (G << 8) | (B << 16) | (A << 24);

と同じ動作をさせたいとき、VBの場合ってどう書けばいいんでしょうか?

bitmapDataはSystem.Drawing.Imaging.BitmapDataクラスです。


投稿者 bz9   (高校生)   投稿日時 2014/8/17 16:42:18
Dim B As Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim G Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim R Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim A Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim rgba As Integer = R Or (G * (2 ^ 8)) Or (B * (2 ^ 16)) Or (A * (2 ^ 24))
こうなると思います。

rgbaに代入している部分のビット演算ですが、
VBでは << のビットシフトは使えないため、2の何乗を掛け算してます。
C#の|はOrです。

投稿者 bz9   (高校生)   投稿日時 2014/8/17 16:44:24
失礼しました、VBでもビットシフトは使えましたね
Dim B As Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim G Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim R Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim A Byte = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
Dim rgba As Integer = R Or (G << 8) Or (B << 16) Or (A << 24)
これで大丈夫だと思います。申し訳ありませんでした。

投稿者 mick   (学生)   投稿日時 2014/8/17 16:56:28
回答ありがとうございます。
やっぱりそうなりますよねー。。
基本独学で学んでるのでこれに関しても今までいろいろ情報は探してきて、
質問前にbz9さんとまったく同じコードで書いてたんですけど、結果がC#で書いたコードと違うのです。。。

それでここのサイトの方たちなら私よりVB.NETは詳しいかなと思い訪ねた次第です><

なぜ結果が変わってしまうのでしょうかね?






投稿者 mick   (学生)   投稿日時 2014/8/17 17:10:07
public static int GetRGBA( byte B, byte G, byte R, byte A)
        {
            int rgba = R | (G << 8) | (B << 16) | (A << 24);
            return rgba;
        }

というメソッドだけC#で作って呼び出した結果、演算が正しく行われてるので、
その部分のみのVB.NETでの記述が違うと思われます。

あ、それと
Dim rgba As Integer = R Or (G * (2 ^ 8)) Or (B * (2 ^ 16)) Or (A * (2 ^ 24))
だとオーバーフローになってしまいます><


投稿者 mick   (学生)   投稿日時 2014/8/17 17:36:18
解決しました★
<<や>>が使えたのでシフト演算子があると思ってましたが、
VB.NETはシフト演算子がないので、そのままかけ算するそうです。
従って、
int rgba = R | (G << 8) | (B << 16) | (A << 24);
をVB.NETで書く場合は
Integerは符号付き32ビットなので、Uint32やUIntegerを使用します。

Dim rgba As UInt32 = R + G * &H100 + B * &H10000 + CType(A, UInt32) * &H1000000

これで正しく処理できました♪

回答してくださった方々、ありがとうございました^^

投稿者 bz9   (高校生)   投稿日時 2014/8/17 17:40:44
あー、多分Byteで計算しちゃってるせいでオーバーフローしてるみたいでしたね

Dim rgba As UInt32 R Or (CInt(G) << 8) Or (CInt(B) << 16) Or (CInt(B) << 24)
これならオーバーフローしませんでした。
検証せずに投稿してしまってごめんなさい

投稿者 bz9   (中学生)   投稿日時 2014/8/17 17:42:46
もう一つ。

http://msdn.microsoft.com/ja-jp/library/2d9yb87a.aspx

Microsoftさんの情報によると VB2013では少なくともこのシフト演算ができるようなので
VBにシフト演算はあるのかな・・・?

自分はVB2010で一つ前の投稿の
Dim rgba As UInt32 R Or (CInt(G) << 8) Or (CInt(B) << 16) Or (CInt(B) << 24)
は正しく動いたっぽかったので、VB2010でもシフト演算は使えそうです。

投稿者 るきお   (社会人)   投稿日時 2014/8/17 17:58:28
VBにも << と >> が使えている以上、もちろんビットシフトの演算が可能です。

ただ、 << と >> の仕様が C# と少し違うので注意が必要なようです。

MSDNライブラリの説明によると、
C#の場合、対象の数値はint, uint, long, ulongであり、byte型については特に触れられていません。
http://msdn.microsoft.com/ja-jp/library/a1sway8w.aspx

一方、VBの場合、上記に加えByteやShortなども対象として扱うことができ、きめ細かくマスクするということが説明されています。
http://msdn.microsoft.com/ja-jp/library/7haw1dex.aspx

そのため、bz9さんが書かれているように自分でC#と同じになるように型変換すると同じ結果が得られます。

ところで、
>やっぱりそうなりますよねー。。
>(中略)
>質問前にbz9さんとまったく同じコードで書いてたんですけど、結果がC#で書いたコードと違うのです。。。
>それでここのサイトの方たちなら私よりVB.NETは詳しいかなと思い訪ねた次第です><
これは、mickさんのためにプログラムを作ってみてくれたbz9さんの善意に対してにちょっと失礼ですね。
本当の意図を隠さないで、はじめからこれを書いてもらえればよかったと思います。
気をつけましょう。


投稿者 mick   (学生)   投稿日時 2014/8/17 18:17:37
>bz9さん、重ねてご回答ありがとうございます。
Dim rgba As UInt32 = R Or (CInt(G) << 8) Or (CInt(B) << 16) Or (CInt(B) << 24)
のほうで試してもオーバーフローしてしまいました。
Dim rgba As UInt32 = R Or (CUInt(G) << 8) Or (CUInt(B) << 16) Or (CUInt(B) << 24)
にしてみたところオーバーフローはしなくなりましたが、やはり演算結果が変わってしまいました><

私の環境はVS2010ですが同じく << や >>が使えるのでシフト演算ができるものと思ってました。
私自身もっと勉強しなおします^^ありがとうございました。

>るきおさんありがとうございます★
MSDNライブラリのほう改めて詳しく読ませていただきます♪

質問の仕方が悪く、不快に思わせてしまったのでしたらbz9さん、るきおさん申し訳ありませんでした。
以後気を付けます。。


投稿者 通りすがり   (社会人)   投稿日時 2014/8/19 11:20:08
>Dim rgba As UInt32 = R Or (CUInt(G) << 8) Or (CUInt(B) << 16) Or (CUInt(B) << 24)
>にしてみたところオーバーフローはしなくなりましたが、やはり演算結果が変わってしまいました><

気になったのですが、
上の式の最後は(CUInt(A) << 24)となるべきですが、(CUInt(B) << 24)と書いてあります。
これが結果の相違の原因ではないですよね?