はじめに
ゲーム制作とかで、可変長引数使いたいと思い、詰まったので覚え書き。
基本
基礎的な部分は以下の記事を参考にしました。
Qiita:C言語 可変長引数関数について 【初心者向け】
やりたいこと
今回、よくあるローグライクゲームを作っていて、
敵からのダメージなどで体力が増減した際、ログを流したいと思いました。
その際、文字列ログを扱うクラスとして、
Messageクラスを作りました。
Message Class
ヘッダファイルはこんな感じ。
Message.h
# pragma once
// Create : 2021/07/05
// Update : 2021/07/05
// Author : Nyarll Creative / UNLUCKY
# ifndef MESSAGE_DEFINED
# define MESSAGE_DEFINED
# include <string>
// Message class
class Message
{
private:
// <Message>
std::string m_value;
public:
Message();
Message(std::string fmt_str, ...);
~Message() = default;
// <文字列設定>
void SetString(std::string fmt_str, ...);
// <文字列の取得>
std::string& GetValue();
};
# endif // Message class
GetValueはm_valueを返しているだけなので省略。
今回は、SetStringについて。
SetString
Message.cpp
void Message::SetString(std::string fmt_str, ...)
{
int final_n, n = ((int)fmt_str.size()) * 2; /* fmt_strの2倍のサイズを予約 */
std::unique_ptr<char[]> formatted;
va_list ap;
while (1)
{
formatted.reset(new char[n]); /* char配列をunique_ptrにラップ */
//strcpy(&formatted[0], fmt_str.c_str());
strcpy_s(&formatted[0], n, fmt_str.c_str());
va_start(ap, fmt_str);
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
va_end(ap);
if (final_n < 0 || final_n >= n)
n += abs(final_n - n + 1);
else
break;
}
m_value = std::string(formatted.get());
}
最初はstrcpyで作り動かしていましたが、もしも就職や転職で成果物として出す場合、
バッファオーバーフローの危険性の孕んでいるstrcpyを利用していると何か言われるかもしれません。
そのため、strcpy_sの利用をおすすめします。
終わりに
これは覚え書きです、ご参考までに。