ページ 11

DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月29日(火) 22:59
by amehirune
お久しぶりでございます、アメヒルネというものです。
本日お尋ねしたいのは、簡単に言いますと「printfを別の関数を経由して実行する」というようなものです。

わかりやすいように例を書きます(実際にわかりやすいかは知りませんが)。

コード:

int printfEx( const char *Strings, ... ){

	return printf(【Stringsの内容を表示(書式付き文字列)】);

}
要するに、printfを「別の関数を経由して」動作させる、というようなものです。

実際にどういった原理を用いてprintfのような処理が行われているのかが分かりませんので、
そこをできれば教えていただきたく思います。

尚、使用している言語はC言語です。
タイトルではDrawFormatStringToHandle関数というDXライブラリの関数を用いておりますが、
実際に知りたいところはそこではなく書式付き文字列の表示の仕方なので、
なにとぞよろしくお願いいたします。

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月29日(火) 23:28
by Dixq (管理人)
そういうのは「可変長引数」といいます。
そのキーワードで検索すると解決しますよ。
例えば以下
http://qiita.com/bamchoh/items/9bec0febc2d30cd1a30e

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月29日(火) 23:32
by Rittai_3D
可変長引数 で調べると幸せになるかもしれません。

http://hitorilife.com/verargs.phpなどが参考になるかもしれません。

#追記 Dixqさんと被ってしまった・・・

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月30日(水) 09:20
by amehirune
申し訳ございませんが、お二方の提示された解説サイトを拝見させていただきましたが、
正直なところ意味が理解できておりません。

どなたか解説を下さらないでしょうか(汗)

va_listはcharのポインタをtypedefで宣言している、というところまではわかっております。
va_start、va_endはファイル入出力でいうオープン・クローズ操作のようなものだと考えております。
まずそこは間違えてはいないでしょうか?

そして先に述べたマクロva_start、va_endはそれぞれ#defineで定義してあるだけのような気がしていて、
それが関数のように扱われていることがまず理解できません。

va_startの第1引数のva_list型ポインタに何らかの文字列が入ることは予想しております。
ですが、第2引数の*Stringだけを渡すのでは、これは意味がないのではないでしょうか。
オフトピック
初めて見る構文ばかりで、正直なところ混乱しておりますので、
日本語的におかしかったり、滅茶苦茶なことを発言してしまっている可能性がありますが、ご了承ください

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月30日(水) 10:03
by Rittai_3D
分かりやすそうなサイトがありましたので、
http://wisdom.sakura.ne.jp/programming/c/c62.html
からva_start と va_end の解説を引用します。
WisdomSoft(旧) さんが書きました: void va_start(va_list リスト , prev);

リストには、引数リストへのポインタを指定します
これは、可変個の引数の情報を保持するための stdarg.h で定義されている標準型です
pervは、最初の可変個数の手前の固定引数を指定します(最後の固定引数)

この時点で va_list 型の変数に、可変引数の情報が格納されます
次に、この va_list 型変数から、順に可変引数の内容を呼び出します
引数リストの値を得るにはva_arg()を使用します
void va_start( va_list arg_ptr, prev_param );
引数リスト arg_ptr の先頭をセットします

ヘッダ - stdarg.h
arg_ptr - 引数リストへのポインタを指定します
prev_param - 最初のオプション引数の直前の引数
最後に、すべての引数を取得したらva_end()でポインタを NULL にリセットします

void va_end(va_list リスト);

リストは、これまでva_start()やva_arg()で引数にアクセスしていた変数です
void va_end( va_list arg_ptr );
引数リストへのアクセスを終了し、ポインタをNULLにします

ヘッダ - stdarg.h
arg_ptr - 引数リストへのポインタを指定します
amehirune さんが書きました:そして先に述べたマクロva_start、va_endはそれぞれ#defineで定義してあるだけのような気がしていて、
それが関数のように扱われていることがまず理解できません。

コード:

#include <stdio.h>

#define PRN		printf

int main(void)
{
	PRN( "ABCDEFG" );
	return 0;
}
実行結果→http://ideone.com/GJOqkI
こういうことをしているだけでは?

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月30日(水) 10:23
by usao
>タイトルではDrawFormatStringToHandle関数というDXライブラリの関数を用いておりますが、
>実際に知りたいところはそこではなく書式付き文字列の表示の仕方なので、

だったら無意味なタイトルを付けなればいいのではないでしょうか.
本当の目的が一体何なのかが読み手にわかりにくくなるだけの効果しかないように思うのです.

結果として(私の読解力が低いだけかもしれませんけど),
vprintf() とか vsprintf() あたりに可変長の部分をうまいこと処理してもらえればそれでいいのか,
それとも
va_arg()を自分で使って一個ずつ引数をあれこれしたいのか
どちらなのかがはっきりと読み取れません.


可変長のとこの仕組みの説明はロベールがわかりやすいように思います.
http://www7b.biglobe.ne.jp/~robe/cpphtm ... 03016.html

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月30日(水) 10:45
by amehirune
ご回答ありがとうございます。
Rittai_3D さんが書きました:分かりやすそうなサイトがありましたので、
http://wisdom.sakura.ne.jp/programming/c/c62.html
ありがとうございます。早速勉強してみることにします。
usao さんが書きました: だったら無意味なタイトルを付けなればいいのではないでしょうか.
本当の目的が一体何なのかが読み手にわかりにくくなるだけの効果しかないように思うのです.

結果として(私の読解力が低いだけかもしれませんけど),
vprintf() とか vsprintf() あたりに可変長の部分をうまいこと処理してもらえればそれでいいのか,
それとも
va_arg()を自分で使って一個ずつ引数をあれこれしたいのか
どちらなのかがはっきりと読み取れません.
いえ、最終的に実行させたいのはDrawFormatStringToHandle関数です。
なので、理想としてはsprintf関数のように、すべての可変長引数の内容を文字配列に代入させ、
それをDrawFormatStringToHandleで表示させたいと考えているのです。
わかりにくくなってしまい、申し訳ありません。

vprintf関数といいますと、こちらが調べてみたところによると
printfとは引数の型が違うだけで動作内容としては全く変わらない…のではないかと思います。
DXライブラリではprintf関連の使用はできませんので、ソースコードに記述することができないのです。

なのでvsprintfこそが私の探していた関数だといえますね。
提示していただきありがとうございます。

私の環境では期待通りの実行結果が得られましたが、可変長引数についてわかるまで勉強するのがよさそうなので、
理解してから解決、とさせていただきたいです。

念のため、無事成功したソースコードのほうを載せさせていただきます。

コード:

int DrawFormatStringToHandleEx(int x,int y,int Color,int FontHandle,const TCHAR *FormatString, ... ){

	char Strings[256];
	va_list list;

	va_start( list,FormatString );
	vsprintf( Strings,FormatString,list );
	va_end( list );

	DrawFormatStringToHandle( x,y,Color,font[FontHandle],Strings );

	return 0;

}
オフトピック
こんな関数作る必要がないでしょ、と思う方もいらっしゃると思うので動機のほうを説明させていただきます。
仮想フルスクリーンモードを実装する際、どうしてもフルスクリーンモードかウィンドウモードかで使用するフォントが違ってきています。
なので、条件分岐を通して文字列を表示する必要があったわけなのですが、その処理をいちいち書いていれば非効率的だと思い、
関数化を図ろうとした次第です。

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年9月30日(水) 11:51
by usao
オフトピック
DXライブラリのことはよくわかりませんが,最後に使うのは
DrawFormatStringToHandle()ではなく
DrawStringToHandle()で良いのではないでしょうか.

あと,vsprintf()はバッファオーバーランに注意が必要です.
https://msdn.microsoft.com/ja-jp/library/28d5ce15.aspx
のRemarksのとことか見ると良いかと思います.

Re: DrawFormatStringToHandle関数を拡張(?)したい

Posted: 2015年10月02日(金) 21:48
by amehirune
勉強したところ、ある程度分かった(ような気がする)ので、解決とさせていただきます。
皆様方、本当にありがとうございました