stringの中身を書式化する場合 – プログラミング – Home

stringの中身を書式化する場合
 
通知
すべてクリア

[解決済] stringの中身を書式化する場合

固定ページ 1 / 2

+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

std::string temp ;
sprintf( &temp[0] , %s %08d 0x%02X , あいう , 100 , 13 ) ;

このようなCと、C++(STL?)の混用は一般的に如何なものでしょうか?
もっとよい書き方があればご教授ねがいます。

因みに、VC7.0で問題なくビルドでき、c_str()できますが、length()の戻り値がとんで
もない値・・・


引用未解決
トピックタグ
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> このような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;
}


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

やっぱりだめですか・・・。
ありがとうございます。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

std::string format(const char* form,...) {
static char buffer[十分大きな領域];
vsprintf(buffer, form, ....);
return buffer;
}

なんてのをこしらえればいぃんじゃないすか?


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

なぜに static なのか?
なぜに vsnprintf ぢゃないのか?
あたりが微妙に疑問。

このへんでいかがざんしょ。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200411/04110017.txt


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

そかそか。
'そのへん'にある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;
}


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

あら?

sprintf( &temp[0] , %s %08d 0x%02X , あいう , 100 , 13 ) ;
はダメで

vsprintf(&buffer[0], format, arguments);
はOKなんですか?


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

最初に十分な大きさを確保してあげてないことが問題なんです。
さらに、出力されるであろう大きさと一致していないと length() に食い違いが生じま
す。
先のコード例では、VC++ではformat後の大きさを返してくれる _vscprintf があればこ
そなわけで、
ポータビリティを求めるならば _vscprintf が使えず、
結果的に十分な大きさのcharバッファを用意せざるを得なくなります。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

GNU libc なら vasprintf が便利っすね

> int result = vsprintf(&buffer[0], format, arguments);
ここでは既に buffer に必要なサイズがきっちり確保され済みなので
vsnprintf である必然も無い、っつーことで。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

...あ、じみにチョンボ。↓これが正解。

#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;
}


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
Topic starter  

あ!
>buffer.assign(length,'\0');
を見落としてました^^;
#そういうことね


返信引用
ひろ
 ひろ
(@ひろ)
ゲスト
結合: 24年前
投稿: 149
 

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 がだめな理由は何でしょう??


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> basic_string &assign(size_type 文字数, char 文字);
> 文字を文字数分繰り返して現在の文字列に割り当てる
>
> なので、文字数+1のサイズが確保されることになるはずです。
> たとえば、buffer.assign(3,'a'); → aaa\0 の4バイト

std::stringが内部に保持する文字列が'\0'終端されている
とは限らない(実装依存)のではありませんか?


返信引用
ひろ
 ひろ
(@ひろ)
ゲスト
結合: 24年前
投稿: 149
 

というと

buffer.assign(4,'a');
printf(%s, buffer.c_str());

こういうコードのときは、STLによっては
いちいちNULL終端の文字列を作ることもあるわけですね。

なんかつかえないなぁ。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

そゆことになるですね。
とはいえ多くの実装では'\0'終端されている、
あるいは文字列の長さ以上の領域が確保されていて、
'\0'を繋ぐコストを抑えていますけども。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました