前から疑問を持っていたので質問してみます。
次のソースを見て下さい。
#include <stdio.h>
int main( void )
{
unsigned char string[] = ABCDEFGHIJKLMNOPQRSTUVWXYZ;
unsigned char *p;
unsigned long n = ('a' - 'A');
printf( 変換前=%s\n, string );
for ( p = string ; *p != '\0' ; p++ ){
*p += (unsigned char)n;
}
printf( 変換後=%s\n, string );
return 0;
}
このソースで
> *p += (unsigned char)n;
の行がコンパイル時に
> warning C4244: '+=' : 'int' から 'unsigned char' に変換しました。
> データが失われているかもしれません。
と出ます。
前に使っていたコンパイラでは警告が出なかったです。
VC2003を使っていて気づきました。
エラーでないため問題なく動作しますが警告メッセージがうっとうしいです。
そこで仕方がなく *p = (unsigned char)(*p + n); と書いていました。
> *p += (unsigned char)n;
この記述では警告が出てしまうものでしょうか?
最初はVC2003のバグ?と思っていましたがどうなのでしょうか?
何か対策ありますか?
ちなみに開発環境は Windows XP + VC2003 です。
新しいコンパイラはまだ買う余裕がありません。
これ以外の警告を消せる対策方法ありますか?
2008では警告レベルを4にしても警告は出ませんでした。
> 2008では警告レベルを4にしても警告は出ませんでした。
これは2008では修正されていると考えて良いのですかね。
普段。警告レベルを4にしてるので。
2005 でも警告が出ますね。
なぜか *p += (unsigned char)n + 0; だと出ないんですが。
> なぜか *p += (unsigned char)n + 0; だと出ないんですが。
さっそく2003でも試してみました。
警告がまったく出なかったです。
不思議です。
2005でも警告が出るんですね。
ちなみにVC2008はWindows XPで問題なく使えるのでしょうか。
使えますよー。
> これ以外の警告を消せる対策方法ありますか?
unsigned char string[] = ABCDEFGHIJKLMNOPQRSTUVWXYZ;
unsigned char *p;
unsigned char n = ('a' - 'A');
printf( 変換前=%s\n, string );
for ( p = string ; *p != '\0' ; p++ ){
*p = *p + n;
}
printf( 変換後=%s\n, string );
こんな感じはいかがでしょうか。
*p += n;
↑こうしてしまうとやはり警告が出ますね。
'+=' の左辺値からの戻りは、型を見ないで
intと決め付けてしまっているのですかね。
ちなみに、'-='でも同じ警告が出ました。
>'+=' の左辺値からの戻りは、型を見ないで
>intと決め付けてしまっているのですかね。
アセンブラレベルで確認すればいい。
> アセンブラレベルで確認すればいい。
2003で見てみました。
>'+=' の左辺値からの戻りは、型を見ないで
>intと決め付けてしまっているのですかね。
この推測があっているとしても、コンパイル時の話なので、
できあがったアセンブリでは確認できないですね。
for ( p = string ; *p != '\0' ; p++ ){
00411A98 lea eax,[string]
00411A9B mov dword ptr [p],eax
00411A9E jmp main+59h (411AA9h)
00411AA0 mov eax,dword ptr [p]
00411AA3 add eax,1
00411AA6 mov dword ptr [p],eax
00411AA9 mov eax,dword ptr [p]
00411AAC movzx ecx,byte ptr [eax]
00411AAF test ecx,ecx
00411AB1 je main+95h (411AE5h)
*p += (unsigned char)n;
00411AB3 movzx eax,byte ptr [n]
00411AB7 mov ecx,dword ptr [p]
00411ABA movzx edx,byte ptr [ecx]
00411ABD add edx,eax
00411ABF mov eax,dword ptr [p]
00411AC2 mov byte ptr [eax],dl
*p += (unsigned char)n + 0;
00411AC4 movzx eax,byte ptr [n]
00411AC8 mov ecx,dword ptr [p]
00411ACB movzx edx,byte ptr [ecx]
00411ACE add edx,eax
00411AD0 mov eax,dword ptr [p]
00411AD3 mov byte ptr [eax],dl
*p = (unsigned char)(*p + n);
00411AD5 mov eax,dword ptr [p]
00411AD8 movzx ecx,byte ptr [eax]
00411ADB add ecx,dword ptr [n]
00411ADE mov edx,dword ptr [p]
00411AE1 mov byte ptr [edx],cl
}
シャノンさん、シュウさん、愛飢え男さん。
書き込みありがとうごうざいま~す。
> 使えますよー。
それじゃVC2008の無料版でもインストールしてみる。
でも無料版はリソースエディタがないからVC2003と共存が
出来ればよいけど。できるかな?
だれか共存して使っている人いますか?
> こんな感じはいかがでしょうか。
テストプログラムなので変数nの型はlongにしているのです。
char型に出来れば最初からその型を使います。
実際には多倍長整数演算のソースをコンパイルしたときに
警告が出るのに気づいたのです。
だからunsigned short型とunsigned long nでも出るんです。
> アセンブラレベルで確認すればいい。
確認できるんですか?
結局はVC2003、VC2005では警告が出てVC2008では出ないのは
ようするにバグと考えてよろしいんですよね。
キャストすれば本来は警告が出ないのが正しい振る舞い。だよね。
C/C++言語の仕様ではどうなんでしょう。
VC6とVC2003で/W4[レベル 4]は警告が出ました。
VC6とVC2003で/W3[レベル 3]は警告が出ません。
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
/W4 [レベル 4]の説明は、
情報を提供する警告を表示します。
ほとんどの場合は無視してもかまわない警告を出力します。
/W4 は、無視できる警告に使用する程度にし、通常の警告レベルでの設定には使用しな
いようにします。
コンパイラの警告 (レベル 3 および 4) C4244の説明は、
'conversion' : 'type1' から 'type2' に変換しました。
データが失われている可能性があります。
整数型がより小さな整数型に変換されました。type2 が int 型で、type1 のサイズが
int 型より小さい場合はレベル 4、それ以外ではレベル 3 の警告となります。
この警告は、次の例のように、整数型間で暗黙の変換が行われる場合にも起こる可能性
があります。
short a, b, c;
a = b + c; // 警告
以上の事から通常はレベルを下げてコンパイルすれば良いと思います。
VC2005とVC2008もあるからインストールしてみるかな。
たいちうさん。
確認わざわざありがとうございま~す。
VC2003、VC2005のバグかしら。
杏の里さんへ。
僕ちゃんはレベル4でコンパイルして警告だけは絶対に出したくない派です。
だから警告をエラー扱いするオプションつけてる。
実行時の不具合はコンパイラでは見つけられませんので最低限として
レベル4で警告が出ないソースをいつも心がけています。
だから無限ループもwhile(1)よりfor(;;)を使います。
よだん
無駄に厳しいチェックをかけてみたければ lint とか。
Free な lint の実装例として split を紹介 (C のみ対象 C++ は対象外)
http://splint.org/
有料でもよければ gimpel の PC-lint for C/C++ (C++ も対象)
http://www.gimpel.com/
まあ -W4 も lint も厳しく警告が出る割にバグが無い保証にならないので
「-W4 で警告が出ないことに自己満足している」に陥らないように注意すべし
>無駄に厳しいチェックをかけてみたければ lint とか。
むかし聞いた事があったがずっと忘れてた。
>まあ -W4 も lint も厳しく警告が出る割にバグが無い保証にならないので
>「-W4 で警告が出ないことに自己満足している」に陥らないように注意すべし
はい。おっしゃるとおりです。
世の中には警告をエラーとは違うから完全無視する人もいるそうです。
僕ちゃんからすると驚きです。
なぜならレベル4の警告でときどき助けられるんですよ。
だからレベル3とかではまずいですし、警告を無視するのもね。
重要な警告を見やすくするためにもキャストして消せる警告は
消したい派なのです。