「C++メモ」カテゴリーのアーカイブ

めっちゃお久しぶりです。

長らくサボってました。今度からもう少しかんがります・・・はい・・・

 

今回はビルド時の警告を消していく時に便利な話です。

 

C++で関数に渡した引数を使用しないと警告がでます。

変数を使用しない状況はオーバーライドしたい時等、色々とありますが、警告が出ると本当に必要な情報が埋もれる時があるので、出来る限り警告は消して生きたいです。

なので、解決策としては変数をvoidにキャストする事で、実行処理としては何も行われませんが、警告は出ない様になります。

キャスト方法としては普通にキャストする時と同じになります。

 


( void )( &testVariable );

 

これを実際の関数に使用するとこんな感じになります:

 


void TestFunction( int testVariable )
{
// voidキャスト
( void )( &testVariable );

// 別パターン
//( void* )( testVariable );
}

 

これだけです。

ただ、これだと何をしているのかパッと見で解りにくいのと、書くのが面倒なのでマクロを書いておくと便利です。

 

// voidキャスト
#define UNUSED_VARIABLE( x ) ( ( void )( &x ) )

void TestFunction( int testVariable )
{
// voidキャスト
UNUSED_VARIABLE( testVariable );
}

 

以上です。

今度からもう少し更新出切る用に・・・ガンバル・・・ガンバル、オレ・・・

タイトル通り、Githubを始めました。

アドレスは以下です:

https://github.com/ookumaneko

主にこのブログに紹介した物を上げていくつもりです。

ただ、前にHDDが死んだ為、一部ソースが残っていない物もある為、それらは書き直す機会があれば上げる、と言う感じになります。

構成としては、XNA, PSM, Unityそれぞれのリポジトリに分かれています。

現状とりあえず幾つかテスト用に上げてあります。そのうちある分は全部上げる予定です。

今回は、C++のプログラム内でログをテキストファイルに簡単に書き込める方法をメモります。

Unrealとかを使っていると、実行時にログを作り、Unreal Script内で書き込めるように指示できます。この機能は意外と約に立つ時があるので今回はC++プログラムで使いまわし出来、基本的な機能が付いているログ作製用のクラスを紹介します。ちなみに、やっている事はテキストファイルに書き込んでいるだけなので簡単です。

 

まずは、ヘッダーファイル内でクラス宣言です。今回は最低限の機能しか付けていないので単純です。クラスには、初期化と書き込み用のメソッドと、ファイル名とファイルへのポインタの変数を宣言しています。

 


class Logger
{
public:
static void Initialize(const std::string& fileName);
static void Write(const std::string& log);

protected:
static std::string fileName;
static FILE* file;

 

全てstatic設定にしているのはプログラム内の何処からでも使用できるためにするためと、使用するのを簡単にするためです。次に、staticの変数と初期化メソッドの実装です。

 


#include <time.h>
#include <Windows.h>

// static変数の初期化
std::string Logger::fileName = "";
FILE* Logger::file = NULL;

void Logger::Initialize(const std::string& fileName)
{
// ファイルの名前を保存
Logger::fileName = fileName;

// ファイルを開き、ポインタを保存
file = fopen( fileName.data(), "w" );

// ファイルが開けなかった場合、
if ( file == NULL )
{
// エラーメッセージを出し、プログラムを終了します。
MessageBox( NULL, "Failed to open log file for writing.\nApplication will be closed now.", "Error Info", MB_ICONWARNING );
exit( 0 );
}
}

 

次は、ログへの書き込み用メソッドの実装です。fprintfでは、ただログを書き込むだけでなく、時間も見やすい形で書き込んでいます(”[ 月日- 時:分:秒 ]: ログ”の順番で)。

 


void Logger::Write(const std::string& log)
{
tm* newTime;
__time64_t longTime;

// 現在の時間を獲得し、ローカル時間(日本の時間)に変換する
_time64( &longTime );
newTime = _localtime64( &longTime );

// 書き込むログの内容を保存する
fprintf( file, "[ %02d月%02d日 - %02d:%02d:%02d ]: %s\n",
newTime->tm_mon + 1, newTime->tm_mday,
newTime->tm_hour, newTime->tm_min, newTime->tm_sec,
log.c_str() );

// ファイルにを書き込む
fflush( file );
}

 

これだけで使えますが、使用を簡易化するためにマクロを書きました。

 

#define LOG( message ) { Logger::Write( message ); }

 

これにより、こんなふうに書けます。

 

LOG( "マクロで書かれたログです" );

 

後は、実際に書き込むだけです。

 

// ログの初期化。現在はプロジェクトのディレクトリに作製されます。
Logger::Initialize( "Log.txt" );

// マクロを使用してのログの書き込み
LOG( "Application Started, written with LOG Macro" );

// そのままの書き込み
Logger::Write( "Printing a Log to Text file" );

 

実行結果:

[ 01月06日 – 02:49:23 ]: Application Started, written with LOG Macro
[ 01月06日 – 02:49:23 ]: Printing a Log to Text file
[ 01月06日 – 02:49:23 ]: Another Log just to test
[ 01月06日 – 02:49:23 ]: Application Closing

 

今回はここまでです。ソースコードが欲しい方がいれば、どこかにアップするか、お送りします。

C++にはC言語で使えたキャスティングとは別に、新しいキャスティングのオペレーターが4つあります。

static_cast<> – static_castは制限が付いたC言語のキャスティングの動作をします。static_castでオブジェクトがキャストされる場合、そのオブジェクトはアップキャストかダウンキャストしか出来ません(継承元となっている親クラスにキャストするか、新たに継承された子クラスにキャストするか)。C++でキャスティングする場合、基本的にはstatic_castを使う方が他のキャスティングより安全で、動作が読みやすいのでオススメです。

const_cast<> – const_castはconst変数からconstを外すか、変更可能な変数にconstを付け加えられます。基本的にconst_cast で必要な機能は自動的にされるので(関数のパラメーターをconst化など)、const_castは使う必要は無い、または使う必要が有る時はデザインを見直したほうが良い時があります。

reinterpret_cast<> – reinterpret_castはC言語のキャストと同じく、どのタイプの変数も関係なくどのタイプにもキャスティングできます。この機能はconst_castと同じく、必要がないのならstatic_castで済ませた方が安全です。

dynamic_cast<> – コレまでのキャスティングは全てコンパイル時に確認され、キャスティングができない時にはエラーが返されますが、dynamic_castはプログラム実行時に動的にキャスティングされます。dynamic_castはC++の既存のデータ型には使えず、プログラマーに作られたクラスをポインターか、参照型で使われている時にだけ使えます。キャストされるため正当な変換かどうかの確認が実行中に行われるため、もしキャスト出来ない変換だった場合はNULLポインターを返します。dynamic_castを使うためにはRTTIが必要(そのうち書き足します)。

注:今回のメモは、参考資料からのもろパクリに近いので、気になる時は参考資料のページを見てください。

C++には五つのメモリ領域(変数、オブジェクトなどを保存する領域)が有り、それぞれ違う用途と特徴が有ります。なお、この記事は簡潔に特徴を書いているので詳しい事は参考資料のページに載っています。

Stack(スタック) – スタックは自動的に作られた変数などを保存します。オブジェクト(変数)は宣言と同時に作成され、そのオブジェクトが作られたスコープから出たら破棄されます。(例:if()文の{}内で宣言されたオブジェクトは、if文の終わりと共に破棄されます)。スタックはヒープなど動的のメモリ領域に比べ構造がシンプルなので、比べると実行速度はかなり早いです。

Heap (ヒープ) – ヒープはmallocを使い動的に宣言された変数を保存するメモリ領域です。

Free Store – Free Storeはnewを使い動的に宣言された変数を保存するメモリ領域です。Newとdeleteはコンパイラによってはmallocとfreeを使い実装されていますが、HeapとFree Storeは別のメモリ領域なので、片方で作られたオブジェクトはもう片方から安全に破棄できるとは限られません。

Const (コンスタント)–  Const領域はコンパイル時に値が解る変数を保存するメモリ領域です(クラスオブジェクトはここには保存されません)。Const領域に保存されている値はプログラムが実行されている限り存在し、値の変更も出来ません。

Global (グローバル) – グローバル領域にはグローバル変数とスタティック変数がプログラムの起動時に割り当てられ、実行時に初期化されます(例:関数内のstatic変数はその関数が始めて呼ばれた時に初期化されます)。

参考元:

Guru of the week #9:

http://www.gotw.ca/gotw/009.htm