質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Q&A

解決済

4回答

2395閲覧

VC++での条件分岐

homepage1031

総合スコア15

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

0グッド

0クリップ

投稿2016/04/21 13:40

###VC++での条件分岐
Visual Studio 2005 Professionalを未だに使用しています。
久しぶりのプログラミングのせいか、自分でミスが見つからないため、
何がいけないのか教えて頂けないでしょうか?

後述するプログラムで、条件分岐で真となり上の方が実行されると思ったのですが、
実際はelseが実行されてしまいます。(ステップ実行で確認)

###該当のソースコード

C++

1static int test_test(void) 2{ 3 char sSrcData[256]; 4 char *ptr1; 5 char *ptr2; 6 7 ptr1 = sSrcData; 8 ptr2 = sSrcData; 9 10 sSrcData[0] = 0xEF; 11 sSrcData[1] = 0xBB; 12 sSrcData[2] = 0xBF; 13 if( (sSrcData[0] == 0xEF) && (sSrcData[1] == 0xBB) && (sSrcData[2] == 0xBF) ){ 14 ptr1+=3; 15 ptr2+=3; 16 }else{ 17 // ここにきてしまう 18 printf("kitayo\n"); 19 } 20 return(0); 21}

アセンブラの情報を見ると以下になっています。

asm

1static int test_test(void) 2{ 300413E10 push ebp 400413E11 mov ebp,esp 500413E13 sub esp,1E4h 600413E19 push ebx 700413E1A push esi 800413E1B push edi 900413E1C lea edi,[ebp-1E4h] 1000413E22 mov ecx,79h 1100413E27 mov eax,0CCCCCCCCh 1200413E2C rep stos dword ptr es:[edi] 1300413E2E mov eax,dword ptr [___security_cookie (417000h)] 1400413E33 xor eax,ebp 1500413E35 mov dword ptr [ebp-4],eax 16 char sSrcData[256]; 17 char *ptr1; 18 char *ptr2; 19 20 ptr1 = sSrcData; 2100413E38 lea eax,[ebp-108h] 2200413E3E mov dword ptr [ebp-114h],eax 23 ptr2 = sSrcData; 2400413E44 lea eax,[ebp-108h] 2500413E4A mov dword ptr [ebp-120h],eax 26 27 sSrcData[0] = 0xEF; 2800413E50 mov byte ptr [ebp-108h],0EFh 29 sSrcData[1] = 0xBB; 3000413E57 mov byte ptr [ebp-107h],0BBh 31 sSrcData[2] = 0xBF; 3200413E5E mov byte ptr [ebp-106h],0BFh 33 if( (sSrcData[0] == 0xEF) && (sSrcData[1] == 0xBB) && (sSrcData[2] == 0xBF) ){ 3400413E65 movsx eax,byte ptr [ebp-108h] 3500413E6C cmp eax,0EFh 3600413E71 jne test_test+9Fh (413EAFh) 3700413E73 movsx eax,byte ptr [ebp-107h] 3800413E7A cmp eax,0BBh 3900413E7F jne test_test+9Fh (413EAFh) 4000413E81 movsx eax,byte ptr [ebp-106h] 4100413E88 cmp eax,0BFh 4200413E8D jne test_test+9Fh (413EAFh) 43 ptr1+=3; 4400413E8F mov eax,dword ptr [ebp-114h] 4500413E95 add eax,3 4600413E98 mov dword ptr [ebp-114h],eax 47 ptr2+=3; 4800413E9E mov eax,dword ptr [ebp-120h] 4900413EA4 add eax,3 5000413EA7 mov dword ptr [ebp-120h],eax 51 }else{ 5200413EAD jmp test_test+0B6h (413EC6h) 53 // ここにきてしまう 54 printf("kitayo\n"); 5500413EAF mov esi,esp 5600413EB1 push offset string "kitayo\n" (4157D4h) 5700413EB6 call dword ptr [__imp__printf (4182F4h)] 5800413EBC add esp,4 5900413EBF cmp esi,esp 6000413EC1 call @ILT+350(__RTC_CheckEsp) (411163h) 61 } 62 return(0); 6300413EC6 xor eax,eax 64}

何が間違っているか教えて頂けないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

こんにちは。

Visual C++のchar型は符号付き8ビットですので、0x80以上0xFF以下の値は負になってしまいます。
ということは、一度char型変数へ0xEFを設定し、これをint型へ戻すと符号拡張されて内部表現的には0xFFFFFFEFとなってしまいます。
しかし、char型変数へ設定していない0xEFはint型のままですので0x000000EFです。
従って、等しくなりません。

char型変数を使った時に時々ハマる罠ですね。

投稿2016/04/21 13:51

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage1031

2016/04/22 13:48

ありがとうございました。 0xFEは1バイトしか書いてなくてもint型なのを失念していました。 遠い昔に同じ事を教えて貰った事を思い出しました。
guest

0

char型の sSrcData と 0xEF という最上位ビットが1の意味ディエイトデータを比較しています。
お使いのコンパイラは、sSrcData の内容を符号拡張(movsxインストラクション)を使い、eax
レジスタに代入して、比較を行っています。

つまり 0xFFFFFFEF と 0x000000EF を比較しています。sSrcData を unsigned にするとか、
比較の時は、両オペランドを unsigned でキャストする等して、符号拡張が起こらないように
する必要があるかと思います。

投稿2016/04/21 13:52

ShinyaAnan

総合スコア241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage1031

2016/04/22 13:52

ありがとうございました。 アセンブラ情報のmovsxを知らなければ調べていれば自分で気がつけたのですね。 なかなかアセンブラは難しくて何がいけないのかあまり分からないですが、 少しは調べるようにします。
guest

0

ベストアンサー

0xEFはint型として評価されます。式の中にcharとintのように異なる型が混在する場合は、サイズの大きい方に暗黙の型変換が行われます。この場合、char型のデータがint型に型変換されることになるのですが、char型の変数に設定された0xEFは-17なのでint型に変換しても符号拡張により-17となります。

対処方法としては右辺をcharでキャストすれば良いですが、よりスマートな実装としては、char型定数として定義する方法がお勧めです。

下記コードを追加し、それぞれの値をBOM8_1~3に置き換えてみてください。

C++

1const char BOM8_1 = 0xEF; 2const char BOM8_2 = 0xBB; 3const char BOM8_3 = 0xBF;

投稿2016/04/21 14:43

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage1031

2016/04/22 13:53

BOMを探しているところまで分かってしまったのですね。 スマートな実装まで教えて頂いたので、ベンストアンサーに選ばせて頂きました。 ありがとうございました。
Chironian

2016/04/22 14:01 編集

catsforepawさん。 あ、今更ですが、EF, BB, BFってどこかで見たようなコードと思ってましたが、UTF-8を示すBOM(Byte Order Mark)ですね。なるほど~。 ところで、爆弾(BOMB)を仕込んではいけませんよ。って、BOM'8'だし。orz (ううっ、被りました。ごめんなさい。)
guest

0

よくわかりませんが…
unsigned char ならいけるんじゃ?

投稿2016/04/21 13:47

takasima20

総合スコア7458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage1031

2016/04/22 13:44

ありがとうございます。 キャストしたら正常に動作しました。 memcmp()なら動く理由が分かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問