#contents
----
ここは憑かれたcoderが %%日頃の憂さ晴らしする%% 自戒する為のページです。書き込みの練習場所 [[SandBox]] ではありません。~

*おことわり
:この手の事象を押さえたい場合はこんなページ見ないで、こういった本を参照して下さい。|&amazon(4798005274,title);
&br;&amazon(475614327X,title);
&br;&amazon(4774117870,title);
&br;&amazon(4756103642,title);
&br;&amazon(4756102107,title);
&br;&amazon(489100455X,title);
&br;&amazon(4891004568,title);
//&br;&amazon(,title);
:[[日本電気通信システム(株) > C言語プログラム品質検証ツール Review-C®:http://rec.ncos.co.jp]]| C言語のよくある間違いをツールでチェックし解説する事で、ソフトウェア開発者の育成とプログラム品質向上に貢献致します。
&br;[[C言語のよくある間違いの解説ページ:http://rec.ncos.co.jp/cgi-bin/errorfrmC.cgi?0]]

*無知との遭遇
**Case1 : if じゃなく always
 bool bParam = false;
 if ( bParam = true ) {
     fprintf( stdout, "orz\n" );
 } else {
     fprintf( stdout, "(^o^)/\n" );
 }
期待出力:(^o^)/~
出力結果:orz~
処 方 箋:比較演算子「==」と代入演算子「=」に注意する。~

**Case2 : 突然の別れ
 static const dParam = 12.0;
 fprintf( stdout, "%lf\n", dParam );
期待出力:12.0~
出力結果:確認不可~
処 方 箋:ちゃんと型宣言する(この場合はdouble or float)。省略した場合は一般的にはint型となる。~

**Case3 : おまえはもう死んでいる
 const char* GetChar( const int& nNo )
 {
    char cBuff[ 4 ];
    ::_snprintf( cBuff, 4, "%d", nNo );
    return cBuff;
 }
 int main( int nArgC, char** ppArgV )
 {
    fprintf( stdout, "%s\n", GetChar( 100 ) );
    return 0;
 }
期待出力:100~
出力結果:解読不可~
処 方 箋:Auto変数のアドレスは返さない。今回は以下の内のどれかの方法で修正する。~
++「return cBuff;」=>「return ::strdup( cBuff );」。但し上位側で%%要 delete[]%% 要 ::free() ←間違えてた。
++「char cBuff[ 4 ];」=>「char* cBuff = new char[ 4 ];」。但し上位側で要 delete[]。
++「const char* GetChar」=>「std::string GetChar」、「return cBuff;」=>「return std::string( cBuff );」

**Case4 : 僕は死にましぇん
 static const char* const DAME_DAME = "orz";
 class CHoge {
 public:
    const char* Get() const { return DAME_DAME; }
 };
 int main( int argc, char* argv[] )
 {
    CHoge* pHoge = NULL;    // ぬるぽ!
    fprintf( stdout, "%s\n", pHoge->Get() );
    return 0;
 }
期待出力:確認不可~
出力結果:orz~
処 方 箋:運良く static な変数のみにアクセスしていたので落ちない。そんなコードは書かないようにする。~

**Case4' : 僕は死にましぇん(Part2)
 class CHoge {
 public:
    static const char* Get() { return "orz"; }
 };
 int main( int argc, char* argv[] )
 {
    CHoge* pHoge = NULL;    // ぬるぽ!
    fprintf( stdout, "%s\n", pHoge->Get() );
    return 0;
 }
期待出力:確認不可~
出力結果:orz~
処 方 箋:static なメソッドの呼び出しは必ず クラス名::メソッド名 で行う。~

**Case5 : 当然の別れ(※VC++のみ)
 try {
     ::AfxThrowUserException();
 catch ( CUserException* pException ) {
    delete pException;
    fprintf( stdout, "orz\n" );
 }
期待出力:orz~
出力結果:確認不可~
処 方 箋:CException::Delete()を呼び出すのが正解。CFile::Remove()でやっている事が多い?
&br;      或いは try〜catch節 をマクロ版 TRY〜CATCH〜END_CATCH に変更し自動で CException::Delete() を呼び出すようにする。~

**Case6 : 自分の後ろに何かいるのが見えない人
 const int nBuffSize = 3;
 struct TDame {
     char cDame[ nBuffSize ];
     int  nDame;
 } stDame = { 0 };
 (void)::strncpy( stDame.cDame, "orz", nBuffSize );
 fprintf( stdout, "%s\n", stDame.cDame );
期待出力:解読不可~
出力結果:orz~
処 方 箋:「¥0」の分を含めたバッファを確保する必要がある。sizeof("orz")は「4」となる。
&br;      構造体の8byteアラインメントにより、char[ 3 ]の後ろに1byte分パディングされている。
&br;      上記の例ではゼロクリアしてるので「orz」+「¥0」となりたまたまうまく動作してしまっている。~

**Case7 : おまえはもう死んでいる(Part2)
 const char* Get( std::auto_ptr<std::string> ptrValue )
 {
    return ptrValue.get()->c_str(); 
 }
 int main(int argc, char* argv[])
 {
    std::auto_ptr<std::string> ptrValue( new std::string( "orz" ) );
    std::auto_ptr< std::string > ptrValue( new std::string( "orz" ) );
    fprintf( stdout, "%s\n", Get( ptrValue ) );
    fprintf( stdout, "%s\n", Get( ptrValue ) );
    return ::_getch();
 }
期待出力:orzorz~
出力結果:「orz」出力後確認不可~
処 方 箋:「std::auto_ptr<std::string> ptrValue」=>「std::auto_ptr<std::string>& ptrValue」
&br;     std::auto_ptrのコピーにより1回目の呼び出し後にインスタンスが破棄されている。~

**Case8 : え・・・そうなん?(※VC++のみ)
 const char* Get()
 {
    __try{     return "(V)゚¥゚(V)"; }
    __finally{ return "orz"; }
 }
 fprintf( stdout, "%s\n", Get() );
期待出力:(V)゚¥゚(V)~
出力結果:orz~
処 方 箋:辛い現実に目を背けず自分の目で確かめて、ありのままを受け入れる。~

**Case9 : ご先祖様も大事だが、今はもっと大事
 std::vector<int> vecHoge( 10 );
 try {
    vecHoge.at( -1 );
 } catch ( exception& e ) { fprintf( stderr, "orz\n" );
 } catch ( std::logic_error& e ) { fprintf( stderr, "Good Job!\n" );
 } catch ( std::out_of_range& e ) { fprintf( stderr, "nice catch!\n" ); }
期待出力:nice catch!~
出力結果:orz~
処 方 箋:基底クラスは後回しにする。~

**Case10 : ツレない人。
 /*******************************************************
 [名称]
      IsValid
 [概要]
      正当性チェック
 [戻り値]
      bool - チェック結果 (ture:正常終了/false:異常終了)
 [引数]
      bChige <IN> - チゲフラグ (ture:チゲ/false:チゲ以外)
      bNabe  <IN> - 鍋フラグ  (ture:鍋/false:鍋以外)
 *******************************************************/
 bool IsValid( const bool& bChige, const bool& bNabe );
処 方 箋:気を抜いていると結構「ture」になっている。~

**Case11 : おまいら typo しる
 bool IsVarid();
 bool SerchValue( const int& );
 int  GetInfomation();
 const char* GetMashineName();
処 方 箋:[[Spelly:http://www.wndtabs.com/spelly/]] でも使ってみる。~

**Case12 : 初心忘れるべからず
 std::vector<int> vecHoge;
 int nResult;    // 初期化ド忘れ
 for ( std::vector<int>::const_iterator itr = vecHoge.begin(); itr != vecHoge.end(); itr++ ) {
     const int& nHoge = (*itr);
     if ( nHoge > 10 ) { nResult = 0;  break; }
     else              { nResult = 1; }
 }
 fprintf( stdout, "%s", ( nResult == 0 ) ? "(V)゚¥゚(V)" : "orz";
期待出力:(V)゚¥゚(V)~
出力結果:orz~
処 方 箋:Auto変数は必ず初期化するという基本に立ち返る。~

**Case13 : 最近連発中・・・
 double dA;
 double dB;
 double dC;
 dA = 1.0 * 2.0;
 dC = 2.0 * 3.0;
 dB = 3.0 * 4.0;
↓変数の宣言時に値を代入するように修正↓
 double dA = 1.0 * 2.0;
 double dB = 2.0 * 3.0;
 double dC = 3.0 * 4.0;
処 方 箋:ちゃんと変数の順番を確認し、テストする。orz~

**Case14 : EffectiveC++の教え
一般的な#define定義で配列の要素数を取得する方法。
 #define ELEMENT_NUMBER(array) ( sizeof( array ) / sizeof( array[ 0 ] ) )
%%EffectiveC++の教えに従って、#defineを使用しない方法。15分位で出来た。%%
 template<typename T>
 static inline int ELEMENT_NUMBER( const T & array )
 { return( sizeof( array ) / sizeof( *array ) ); }
もっとより良い方法
 template< typename T, size_t N >
 static inline int ELEMENT_NUMBER( T (&) [ N ] )
 { return N; }
とりあえずVC++6.0〜8.0/g++4.1では上手く動いた。

**Case15 : B級ループ
 char* pcTemp = NULL;
 while ( 1 ) {
    const int nBuffSize = 10;
    try {
        pcTemp = new char[ nBuffSize ];
    } catch ( std::badalloc& e ) {
    } catch ( std::bad_alloc& e ) {
        fprintf( stderr, "%s(%d) : %s\n", __FILE__, __LINE__, e.what() );
        ::exit( -1 );
    }
    if ( bFlag1 ) {
        fprintf( stderr, "%s(%d) : Error@bFlag1\n", __FILE__, __LINE__ );
        break;
    }
    ・・・・
    // break; の書き忘れで永久ループ・・・orz
 }
 if ( pcTemp != NULL ) delete [] pcTemp;
while文でgoto的なコードを書いて、最後に「break;」書き忘れ。~
デバッグしたら直ぐに分かるバグだが、最近は以下のように記述するようにしている。
 char* pcTemp = NULL;
 do {
    ・・・・
 } while ( 0 );
 if ( pcTemp != NULL ) delete [] pcTemp;
処 方 箋:適材適所 do〜while にも有用な場面が有る事を肝に銘じる。

**Case16 : VCおまえだけか!
 #include <stdlib.h>
 int main( int argc, char** argv )
 {
 #ifndef DEF_VALUE
 #define DEF_VALUE
 #endif  DEF_VALUE   /*コメントアウトし忘れ?*/
     return 0;
 }
|コンパイラ|コンパイル結果|h
|VisualC++ 6.0|警告レベル4(/W4)でもエラーなし。|
|VisualC++ 7.1|警告レベル4(/W4)でもエラーなし。|
|MIPSpro 7.4.2m|cc-1014 cc: WARNING&br;Invalid characters appear before a new-line in the preprocessor directive.|
|gcc 3.3.3|warning: extra tokens at end of #endif directive|

**Case17 : いつもより余計に回し・・・たらアカンて。
> &ref(STLeraseSample.tar.bz2,JunkBox);

**Case18 : 大容量のワイドな文字列で、顔面真っ青
 int main(int argc, char* argv[])
 {
    (void)::setlocale( LC_ALL, "japanese" );
     fprintf( stdout,  "%s, %S\n", "orz", L"orz" );
    fwprintf( stdout, L"%S, %s\n", "orz", L"orz" );
    return ::fgetc( stdin );
 }
処 方 箋:[[MSDN > printf 関数の型フィールド文字:http://msdn.microsoft.com/ja-jp/library/hf4y5e3w.aspx]], [[Manpage of PRINTF:http://www.linux.or.jp/JM/html/LDP_man-pages/man3/printf.3.html]]~
|環境|API|const char*|const wchar_t*|h
|VC++|printf/fprintf|''%s''(small s)|''%S''(large s)|
|VC++|wprintf/fwprintf|''%S''(large s)|''%s''(small s)|
|UNIX系|printf/fprintf|''%s''(small s)|''%ls''|
|UNIX系|wprintf/fwprintf|''%s''(small s)|''%ls''|

**Case19 : 今更ながら・・・それ間違ってますから〜〜〜残念!(※VC++のみ)
 wchar_t cBuff[ 10 ];
 const wchar_t* const pwcInputValue = L"0123456789ABCDEF";
 (void)::_snwprintf( cBuff, sizeof( cBuff ), L"%s", pwcInputValue );
期待出力:0123456789~
出力結果:確認不可男~
処 方 箋:ちゃんと [[リファレンス:http://msdn.microsoft.com/ja-jp/library/2ts7cx93.aspx]] を読む。「n」が付くsnprintf, strncpy等のサイズにはバイト数ではなく、文字数を指定する。
&br;     因みにVC++の_snprintfは [[UNIX系のsnprintf:http://www.linux.or.jp/JM/html/LDP_man-pages/man3/snprintf.3.html]] とは挙動が異なり、サイズで指定した文字数には終端のヌル文字列は含まれない。
&br;     下記のようなコード &ref(snprintf_test.tar.bz2); であればとりあえず問題無し。
 const int nBuffSize = 10;
 TCHAR cBuff[ nBuffSize + 1 ];  // ヌル文字分を別途確保
 const TCHAR* const pcInputValue = _T("0123456789ABCDEF");
 cBuff[ nBuffSize ] = 0;  // ヌル文字分領域にヌル文字をセットしておく
 (void)::_sntprintf( cBuff, nBuffSize, _T("%s"), pcInputValue );

**Case20 : 環境破壊(※VC++のみ)
 (void)::SetEnvironmentVariable( "OREORE", "DARESORE" );
 (void)::fprintf( stdout, "%s\n", ::getenv( "OREORE" ) );
期待出力:"DARESORE"~
出力結果:""(長さゼロの文字列)~
処 方 箋:SetEnvironmentVariable()で設定された環境変数は、GetEnvironmentVariable()でのみ取得可能となる。
&br;     逆に_putenv()で設定した環境変数は、GetEnvironmentVariable()でも取得可能である。

**Case21 : 痛恨の一撃
 「regist」という英語単語は存在しない。「register」とするのが正しい。
元 ネ タ: http://labs.cybozu.co.jp/blog/akky/archives/2005/07/regist.html ~
処 方 箋:&amazon(4469041580,title); でも手元に置いておくべし。

ページ先頭へ   最終更新のRDF 最終更新のRSS
Valid XHTML 1.1 Valid CSS! [Valid RSS]