std::string temp ;
sprintf( &temp[0] , %s %08d 0x%02X , あいう , 100 , 13 ) ;
このようなCと、C++(STL?)の混用は一般的に如何なものでしょうか?
もっとよい書き方があればご教授ねがいます。
因みに、VC7.0で問題なくビルドでき、c_str()できますが、length()の戻り値がとんで
もない値・・・
> このようなCと、C++(STL?)の混用は一般的に如何なものでしょうか?
極めて危険。やってはいけない。動いたとしてもたまたま動いてくれただけ。
> もっとよい書き方があればご教授ねがいます。
sprintfを使いたいなら
char temp[余裕をもった大きさ];
余裕をもった大きさが見積もれず、stringを使いたいのなら
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
int main() {
ostringstream stream;
stream << あいう << ' '
<< setfill('0') << setw(8) << 100 << ' '
<< hex << setiosflags(ios_base::uppercase) << setw(2) << 13;
string temp = stream.str();
cout << '[' << temp << ']' << endl;
}
やっぱりだめですか・・・。
ありがとうございます。
std::string format(const char* form,...) {
static char buffer[十分大きな領域];
vsprintf(buffer, form, ....);
return buffer;
}
なんてのをこしらえればいぃんじゃないすか?
なぜに static なのか?
なぜに vsnprintf ぢゃないのか?
あたりが微妙に疑問。
このへんでいかがざんしょ。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200411/04110017.txt
そかそか。
'そのへん'にあるBanさんのをパクらせていただきました。
#include <cstdio>
#include <cstdarg>
#include <cassert>
#include <string>
std::string form(const char* const format, ...) {
va_list arguments;
std::string buffer;
assert(format);
va_start(arguments, format);
try{
int length = _vscprintf(format, arguments) ;
if(length < 0) throw std::runtime_error(format);
buffer.assign(length,'\0');
int result = vsprintf(&buffer[0], format, arguments);
if(result < 0) throw std::runtime_error(format);
} catch(...) {
va_end(arguments);
throw;
}
va_end(arguments);
return buffer;
}
#include <iostream>
int main() {
std::cout << '[' << form(%s %08d 0x%02X , あいう , 100 , 13 ) << ']' <<
std::endl;
}
あら?
sprintf( &temp[0] , %s %08d 0x%02X , あいう , 100 , 13 ) ;
はダメで
vsprintf(&buffer[0], format, arguments);
はOKなんですか?
最初に十分な大きさを確保してあげてないことが問題なんです。
さらに、出力されるであろう大きさと一致していないと length() に食い違いが生じま
す。
先のコード例では、VC++ではformat後の大きさを返してくれる _vscprintf があればこ
そなわけで、
ポータビリティを求めるならば _vscprintf が使えず、
結果的に十分な大きさのcharバッファを用意せざるを得なくなります。
GNU libc なら vasprintf が便利っすね
> int result = vsprintf(&buffer[0], format, arguments);
ここでは既に buffer に必要なサイズがきっちり確保され済みなので
vsnprintf である必然も無い、っつーことで。
...あ、じみにチョンボ。↓これが正解。
#include <cstdio>
#include <cstdarg>
#include <cassert>
#include <string>
std::string form(const char* const format, ...) {
va_list arguments;
std::string buffer;
assert(format);
va_start(arguments, format);
try{
int length = _vscprintf(format, arguments) ;
if(length < 0) throw std::runtime_error(format);
buffer.assign(length+1,'\0');
int result = vsprintf(&buffer[0], format, arguments);
if(result < 0) throw std::runtime_error(format);
buffer.erase(length,1);
} catch(...) {
va_end(arguments);
throw;
}
va_end(arguments);
return buffer;
}
#include <iostream>
int main() {
std::cout << '[' << form(%s %08d 0x%02X , あいう , 100 , 13 ) << ']' <<
std::endl;
}
あ!
>buffer.assign(length,'\0');
を見落としてました^^;
#そういうことね
STLは使ったことがないのでよくわかりませんが、
2007/09/20(木) 15:50:58 でいいような気がします。
assign()はググると
basic_string &assign(size_type 文字数, char 文字);
文字を文字数分繰り返して現在の文字列に割り当てる
なので、文字数+1のサイズが確保されることになるはずです。
たとえば、buffer.assign(3,'a'); → aaa\0 の4バイト
なので、
buffer.assign(length+1,'\0'); → buffer.length()がlength+1になってしまう?
:
buffer.erase(length,1); → buffer.length()をlengthにしている?
は必要ないのでは?
2007/09/20(木) 15:50:58 がだめな理由は何でしょう??
> basic_string &assign(size_type 文字数, char 文字);
> 文字を文字数分繰り返して現在の文字列に割り当てる
>
> なので、文字数+1のサイズが確保されることになるはずです。
> たとえば、buffer.assign(3,'a'); → aaa\0 の4バイト
std::stringが内部に保持する文字列が'\0'終端されている
とは限らない(実装依存)のではありませんか?
というと
buffer.assign(4,'a');
printf(%s, buffer.c_str());
こういうコードのときは、STLによっては
いちいちNULL終端の文字列を作ることもあるわけですね。
なんかつかえないなぁ。
そゆことになるですね。
とはいえ多くの実装では'\0'終端されている、
あるいは文字列の長さ以上の領域が確保されていて、
'\0'を繋ぐコストを抑えていますけども。