ここは憑かれたcoderが 日頃の憂さ晴らしする 自戒する為のページです。書き込みの練習場所 SandBox ではありません。
bool bParam = false; if ( bParam = true ) { fprintf( stdout, "orz\n" ); } else { fprintf( stdout, "(^o^)/\n" ); }
期待出力:(^o^)/
出力結果:orz
処 方 箋:比較演算子「==」と代入演算子「=」に注意する。
static const dParam = 12.0; fprintf( stdout, "%lf\n", dParam );
期待出力:12.0
出力結果:確認不可
処 方 箋:ちゃんと型宣言する(この場合はdouble or float)。省略した場合は一般的にはint型となる。
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変数のアドレスは返さない。今回は以下の内のどれかの方法で修正する。
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 な変数のみにアクセスしていたので落ちない。そんなコードは書かないようにする。
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 なメソッドの呼び出しは必ず クラス名::メソッド名 で行う。
try { ::AfxThrowUserException(); catch ( CUserException* pException ) { delete pException; fprintf( stdout, "orz\n" ); }
期待出力:orz
出力結果:確認不可
処 方 箋:CException::Delete()を呼び出すのが正解。CFile::Remove()でやっている事が多い?
或いは try〜catch節 をマクロ版 TRY〜CATCH〜END_CATCH に変更し自動で CException::Delete() を呼び出すようにする。
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」となる。
構造体の8byteアラインメントにより、char[ 3 ]の後ろに1byte分パディングされている。
上記の例ではゼロクリアしてるので「orz」+「¥0」となりたまたまうまく動作してしまっている。
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" ) ); 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」
std::auto_ptrのコピーにより1回目の呼び出し後にインスタンスが破棄されている。
const char* Get() { __try{ return "(V)゚¥゚(V)"; } __finally{ return "orz"; } } fprintf( stdout, "%s\n", Get() );
期待出力:(V)゚¥゚(V)
出力結果:orz
処 方 箋:辛い現実に目を背けず自分の目で確かめて、ありのままを受け入れる。
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
処 方 箋:基底クラスは後回しにする。
/******************************************************* [名称] IsValid [概要] 正当性チェック [戻り値] bool - チェック結果 (ture:正常終了/false:異常終了) [引数] bChige <IN> - チゲフラグ (ture:チゲ/false:チゲ以外) bNabe <IN> - 鍋フラグ (ture:鍋/false:鍋以外) *******************************************************/ bool IsValid( const bool& bChige, const bool& bNabe );
処 方 箋:気を抜いていると結構「ture」になっている。
bool IsVarid(); bool SerchValue( const int& ); int GetInfomation(); const char* GetMashineName();
処 方 箋:Spelly でも使ってみる。
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変数は必ず初期化するという基本に立ち返る。
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
一般的な#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では上手く動いた。
char* pcTemp = NULL; while ( 1 ) { const int nBuffSize = 10; try { pcTemp = new char[ nBuffSize ]; } 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 にも有用な場面が有る事を肝に銘じる。
#include <stdlib.h> int main( int argc, char** argv ) { #ifndef DEF_VALUE #define DEF_VALUE #endif DEF_VALUE /*コメントアウトし忘れ?*/ return 0; }
コンパイラ | コンパイル結果 |
VisualC++ 6.0 | 警告レベル4(/W4)でもエラーなし。 |
VisualC++ 7.1 | 警告レベル4(/W4)でもエラーなし。 |
MIPSpro 7.4.2m | cc-1014 cc: WARNING Invalid characters appear before a new-line in the preprocessor directive. |
gcc 3.3.3 | warning: extra tokens at end of #endif directive |
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 関数の型フィールド文字, Manpage of PRINTF
環境 | API | const char* | const wchar_t* |
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 |
wchar_t cBuff[ 10 ]; const wchar_t* const pwcInputValue = L"0123456789ABCDEF"; (void)::_snwprintf( cBuff, sizeof( cBuff ), L"%s", pwcInputValue );
期待出力:0123456789
出力結果:確認不可男
処 方 箋:ちゃんと リファレンス を読む。「n」が付くsnprintf, strncpy等のサイズにはバイト数ではなく、文字数を指定する。
因みにVC++の_snprintfは UNIX系のsnprintf とは挙動が異なり、サイズで指定した文字数には終端のヌル文字列は含まれない。
下記のようなコード 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 );
(void)::SetEnvironmentVariable( "OREORE", "DARESORE" ); (void)::fprintf( stdout, "%s\n", ::getenv( "OREORE" ) );
期待出力:"DARESORE"
出力結果:""(長さゼロの文字列)
処 方 箋:SetEnvironmentVariable()で設定された環境変数は、GetEnvironmentVariable()でのみ取得可能となる。
逆に_putenv()で設定した環境変数は、GetEnvironmentVariable()でも取得可能である。
「regist」という英語単語は存在しない。「register」とするのが正しい。
元 ネ タ: http://labs.cybozu.co.jp/blog/akky/archives/2005/07/regist.html
処 方 箋:https://www.amazon.co.jp/dp/4469041580
でも手元に置いておくべし。