Windows 開発で、
Android ネイティブアプリ開発では、画面表示には文字列は(今のところ)使いませんが、 ログ記録では使いたかったので、とりあえず最低限欲しかった機能を持ったクラスを作成しました。
ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
また、本サイトが初めての方は、まずこのページの注意事項をご覧ください。
投稿 October 12, 2018
すでにご存じの方は、このセクションは飛ばしていただいて構いません。
文字列の代入や結合は、C/C++ では次のようになるかと思います。
char text[256]; strcpy(text, "hello,"); strcat(text, "developers.");
text に入れる文字列のサイズにより、バッファーオーバーランが起きたりしますから、危険もあります。 上記の例では、char text[8]; と定義した場合などです。
MFC の CString クラスを使うと、次のように書けます。
CString strText; strText = "hello,"; strText += "developers.";
sprintf のような機能も持っています。
sprintf(text, "The value is %d.", 150);
strText.Format("The value is %d.", 150);
_sprintf でリンクエラーを回避する
古い Visual C++ プロジェクトを新しい Visual C++ プロジェクトに変換したとき、_sprintf 関数がエラーになる場合の回避方法について書いています。
文字列比較や部分取り出し、文字列検索など、ほかにもたくさんの機能がありますが、 今はログ出力する文字列を作成するのに便利に使えそうな機能を、代用のクラスで使えるようにしました。
投稿 October 12, 2018
まずは、今回実装したクラスのヘッダーを記載します。 実際には、このようなクラスを集められるよう、また念のためクラス名が重ならないよう、ネームスペースに追加しています。
class CmxString { public: // コンストラクター 詳細 CmxString(); CmxString(const char* text); // デストラクター 詳細 ~CmxString(); /** * 確保したメモリを解放します。 詳細 */ void Empty(void); /** * 代入演算 詳細 * 指定の文字列のサイズだけメモリを確保して、保持します。 */ CmxString& operator = (const char* text); /** * 自身に対する和差積商演算(+=、-=、*=、/=) 詳細 * CmxString を引数としても、char* にキャストされればこれで対応できます。 */ CmxString& operator += (const char* text); /** * 比較演算(==、!=、<、>) 詳細 * == オペレーターで、Compare と同じ働きを期待できます。 */ bool operator == (const char* text) const; /** * char* へのキャスト演算子 */ operator char*() const { if (m_text) { return m_text; } return NULL; } protected: // 内部管理メモリ char* m_text; };
クラス名は、CmxString としていますが、もちろん何でも構いません。
投稿 October 12, 2018
CmxString();
CmxString(char* text);
の2種類を用意しました。
使い方としては、
CmxString str;
str = "hello";
としてもいいし、
CmxString str("hello");
としてもいい、という具合です。
いずれも、char* m_text に NULL を設定して、メモリを確保していない状態とします。
最初から値を設定するコンストラクターとしては、operator = 演算子で、自身に文字列を設定しています。 この設定については、operator = 演算子の定義をご覧ください。
CmxString::CmxString() : m_text(NULL) { } CmxString::CmxString(const char* text) : m_text(NULL) { *this = text; }
投稿 October 12, 2018
デストラクターでは、char* m_text にメモリが確保されている場合には解放する、 Empty 関数を呼び出しています。 この関数については、後述の Empty 関数をご参照ください。
CmxString::~CmxString() { Empty(); }
投稿 October 12, 2018
確保したメモリを解放する関数です。 CString::Empty() と同じイメージです。
使用者が明示的にメモリを解放したい場合にも使えますが、 通常は、デストラクターから自動的に呼び出されますので、気にする必要はありません。
void CmxString::Empty(void) { if (m_text) { free(m_text); m_text = NULL; } }
投稿 October 12, 2018
CmxString str;
str = "hello";
のように、文字列をイコールで代入できるようにしています。
CmxString& CmxString::operator = (const char* text) { size_t length; Empty(); // 引数が NULL のとき if (!text) { return *this; } // 指定文字列のサイズだけメモリを確保します。 length = strlen(text) + 1; // 終端 NULL 用の1バイトを追加 if (!(m_text = (char*)malloc(length))) { return *this; } // 文字列をコピーします。 memset(m_text, 0, length); memcpy(m_text, text, length - 1); return *this; }
投稿 October 12, 2018
引数で指定された文字列を自身に結合します。
str = "hello, ";
str += "world!";
のように使います。
ヘッダーに char* へのキャストを記述していますので、
str = "hello,";
str1 = "world!";
str += str1;
のようにも使えます。
CmxString& CmxString::operator += (const char* text) { size_t length, newLength; void* data; char* ptr; // 引数が NULL のときは、何もしません。 if (!text) { return *this; } // 追加する文字列がなければ、何もしません。 length = strlen(text); if (length < 1) { return *this; } // 自身が NULL であるなら、単なる設定になります。 if (!m_text) { *this = text; return *this; } // 必要なサイズの新しいメモリを確保します。 newLength = strlen(m_text) + length + 1; if (!(data = malloc(newLength))) { return *this; // メモリを確保できず、追加せず終了します } // 新しく確保したメモリにコピーします。 memset(data, 0, newLength); memcpy(data, m_text, strlen(m_text)); // もとのテキストをコピーします ptr = ((char*)data) + strlen(m_text); memcpy(ptr, text, length); // 追加するテキストをコピーします // もとのメモリを解放して、新しいメモリをポイントします。 Empty(); m_text = (char*)data; return *this; }
投稿 October 12, 2018
CString::Compare 関数と同じイメージです。 戻り値は int 値ではなく、true または false です。
if (str == "option1"){
// オプション1の処理
}
のように比較できます。
CString::CompareNoCase 関数とは異なり、アルファベットの大文字・小文字も区別されます。
bool CmxString::operator == (const char* text) const { // 自身に文字列が設定されていないときは、一致にはなりません。 if (!m_text) { return false; } // 引数を検査しておきます。 if (!text) { return false; } // サイズが異なれば、一致にはなりません。 size_t size1 = strlen(m_text); size_t size2 = strlen(text); if (size1 != size2) { return false; } // 1文字づつ比較します。 for (size_t i = 0; i < size1; i++) { if (m_text[i] != text[i]) { return false; } } // すべての文字が一致すれば、一致と判断します。 return true; }
Android 開発に関する記事をまとめた Android 開発トップ もご覧ください。