トップ回答者
C#からsprintf

質問
回答
-
諸農です。
Myon さんからの引用 C++等を経由すればできるかも知れませんが、unmanageの経験がほとんどなく、困っております。
セキュリティが強化されたsprintf関数がVC++2005で使えるようですので、C#から呼び出し可能なライブラリを作ってみるというのはいかがでしょうか?
http://msdn2.microsoft.com/ja-jp/library/ce3zzk1k.aspx
-
どうやってクラスライブラリを使うかはよくわかりませんけど、VC++で作るとしたら、
C#側ではアンマネージドを意識しないように作られたほうがよいでしょう。つまり
String^ Spritnf( String^ format, array< Object^ >^ obj ) { wchar_t buff[ 256 ]; va_list args; // objから args をつくる。作り方は忘れたw
vswprintf( buff, PtrToStringChars( format ), args ); return gcnew String( buff ); }みたいなかんじに。
-
やはり、C言語のsprintfのようにいくつもの要素を渡してというのは難しそうです。
ですので、 %~ に対して,1つの要素を渡して変換という風にちょっとヘボいですが
そんな感じにして、C#側で連結してあげるのはどうでしょうか?C#public ref class Class1 { public: // int型用 static String^ Sprintf( String^ format, int n ) { wchar_t buff[ 256 ]; swprintf_s( buff, 256, PtrToStringChars( format ), n );
return gcnew String( buff ); } // short型用 // 略 // long型用 // 略 // float型用 // 略 // double型用 // 略 // int64型用 // 略 // String型用 static String^ Sprintf( String^ format, String^ str ) { wchar_t buff[ 256 ]; swprintf_s( buff, 256, PtrToStringChars( format ),
PtrToStringChars( str ) ); return gcnew String( buff ); } }int n = 10; double d = 2.5; // 本当は "%2d%g" としたいが、できないので下のように1要素ずつ変換させる string s = Class1.Sprintf("%2d",n) + Class1.Sprintf("%g", d);
すべての返信
-
諸農です。
Myon さんからの引用 C++等を経由すればできるかも知れませんが、unmanageの経験がほとんどなく、困っております。
セキュリティが強化されたsprintf関数がVC++2005で使えるようですので、C#から呼び出し可能なライブラリを作ってみるというのはいかがでしょうか?
http://msdn2.microsoft.com/ja-jp/library/ce3zzk1k.aspx
-
どうやってクラスライブラリを使うかはよくわかりませんけど、VC++で作るとしたら、
C#側ではアンマネージドを意識しないように作られたほうがよいでしょう。つまり
String^ Spritnf( String^ format, array< Object^ >^ obj ) { wchar_t buff[ 256 ]; va_list args; // objから args をつくる。作り方は忘れたw
vswprintf( buff, PtrToStringChars( format ), args ); return gcnew String( buff ); }みたいなかんじに。
-
やはり、C言語のsprintfのようにいくつもの要素を渡してというのは難しそうです。
ですので、 %~ に対して,1つの要素を渡して変換という風にちょっとヘボいですが
そんな感じにして、C#側で連結してあげるのはどうでしょうか?C#public ref class Class1 { public: // int型用 static String^ Sprintf( String^ format, int n ) { wchar_t buff[ 256 ]; swprintf_s( buff, 256, PtrToStringChars( format ), n );
return gcnew String( buff ); } // short型用 // 略 // long型用 // 略 // float型用 // 略 // double型用 // 略 // int64型用 // 略 // String型用 static String^ Sprintf( String^ format, String^ str ) { wchar_t buff[ 256 ]; swprintf_s( buff, 256, PtrToStringChars( format ),
PtrToStringChars( str ) ); return gcnew String( buff ); } }int n = 10; double d = 2.5; // 本当は "%2d%g" としたいが、できないので下のように1要素ずつ変換させる string s = Class1.Sprintf("%2d",n) + Class1.Sprintf("%g", d);
-
申し訳ありませんが、関連でもう一問お願いしたいのです。(C++の話なので掲示板違いになりまして申し訳ありません)
swprintf_sを使って上のようにやっておりましてうまく行ってるのですが、フォーマット文字列に変なものを入れるとswprintf_sで落ちてしまいます(%t等)。try-catchもやっていますがどうしても落ちるようです。エラーメッセージは「Debug Assertion Failed state != ST_INVALID」です。セキュリティが強化されたswprintf_sのヘルプを見るとフォーマットエラーは戻り値でエラーを返してくれると書いてあるのですが。宜しくお願い致します。
-
よく、MSDNをよんでみたところ、printf、_printf_l、wprintf、_wprintf_l のパラメータの検証より、
とありました。無効なパラメータが見つかると、C ランタイムは、現在割り当てられている無効なパラメータ ハンドラを呼び出します。既定の無効なパラメータ ハンドラは、アクセス違反例外を発生させます。この場合、通常、実行が続行不能になります。デバッグ モードでは、アサーションも発生します。また、Watson クラッシュ レポートを既定の設定のまま有効にしている場合、アプリケーションがクラッシュし、Microsoft に対して分析用にクラッシュ ダンプを読み込むかどうかをたずねるメッセージが表示されます。
この動作は、無効なパラメータ ハンドラを独自の関数に設定する _set_invalid_parameter_handler 関数を使用することにより、変更できます。指定した関数がアプリケーションを終了する場合、無効なパラメータを受け取った関数に制御が戻ります。これらの関数は通常、実行が停止し、エラー コードを返し、errno をエラー コードに設定します。多くの場合、errno 値と戻り値は両方とも EINVAL になり、無効なパラメータを示します。場合によっては、より具体的なエラー コードが返ります。たとえば、パラメータとして渡された無効なファイル ポインタを示す EBADF などです。errno の詳細については、「errno、_doserrno、_sys_errlist、および _sys_nerr」を参照してください。
_set_invalid_parameter_handler のリンク先をよむと、ちゃんとerrnoで確認できるように記述でるようです。 -
ありがとうございました。戻り値でエラーを取得することができました。結局以下のようなコードになりました(HTML上できれいに表示する方法がわからないので見にくくてすいません)。return "";なんてやってますがNULLを返せれば理想的なのですが・・・。
また、フォーマット文字列はユーザーから渡されるものなのでチェックする必要がありました。
#include <stdio.h>
#include <vcclr.h>
#include <stdlib.h>
#include <crtdbg.h> // For _CrtSetReportMode
void myInvalidParameterHandler(const wchar_t* expression,const wchar_t* function, const wchar_t* file,unsigned int line, uintptr_t pReserved)
{
wprintf(L"Invalid parameter detected in function %s."
L" File: %s Line: %d\n", function, file, line);
wprintf(L"Expression: %s\n", expression);
}
// int型用
static String^ Sprintf( String^ format, int value )
{
try
{
_invalid_parameter_handler oldHandler, newHandler;
newHandler = myInvalidParameterHandler;
oldHandler = _set_invalid_parameter_handler(newHandler);
// Disable the message box for assertions.
_CrtSetReportMode(_CRT_ASSERT, 0);
int nRet;
wchar_t buff[ 256 ];
pin_ptr<const wchar_t> p = PtrToStringChars( format );
nRet = swprintf_s( buff, 255, p, value );
if( nRet < 0 )
{
return "";
}
return gcnew String( buff );
}
catch( Exception^ ex )
{
return "";
}
}
-
Myon さんからの引用 return "";なんてやってますがNULLを返せれば理想的なのですが・・・。
nullptrを返すことはできなかったかなぁ。
また、クラスライブラリからまた例外を投げるというのもアリかなと。(出来るのかは確かではないが。)Myon さんからの引用 HTML上できれいに表示する方法がわからないので見にくくてすいません
BBコードと呼ばれるものをつかうと、きれいに(?)コードを表示できます。
参考: http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=227443&SiteID=7 -
nullptrを知りませんでした。bbcodeのリンクもありがとうございます。
#include <stdio.h>
#include <vcclr.h>
#include <stdlib.h>
#include <crtdbg.h> // For _CrtSetReportMode
void myInvalidParameterHandler(const wchar_t* expression,const wchar_t* function, const wchar_t* file,unsigned int line, uintptr_t pReserved)
{
wprintf(L"Invalid parameter detected in function %s."
L" File: %s Line: %d\n", function, file, line);
wprintf(L"Expression: %s\n", expression);
}
// int型用
static String^ Sprintf( String^ format, int value )
{
try
{
_invalid_parameter_handler oldHandler, newHandler;
newHandler = myInvalidParameterHandler;
oldHandler = _set_invalid_parameter_handler(newHandler);
// Disable the message box for assertions.
_CrtSetReportMode(_CRT_ASSERT, 0);
int nRet;
wchar_t buff[ 256 ];
pin_ptr<const wchar_t> p = PtrToStringChars( format );
nRet = swprintf_s( buff, 255, p, value );
if( nRet < 0 )
{
return nullptr;
}
return gcnew String( buff );
}
catch( Exception^ ex )
{
return nullptr;
}
}
-
いまさらですけど、C#からでもCの可変個引数を可変個引数として渡せるようですよ。