可変長の自作関数を作りたいがうまくできない…

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ピーちゃん

可変長の自作関数を作りたいがうまくできない…

#1

投稿記事 by ピーちゃん » 9年前

DXライブラリの関数をまねて自作関数として置き換えたいと思っています。
(理由:関数名をなるべく省略したいからです。)

例としてDrawFormatString関数をprint関数に置き換えるように作ってみました。

コード:

/********** game.h **********/
#include "DxLib.h"
#include "dxLibFunction.h"

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE);	//set window mode
        DxLib_Init();   // DXライブラリ初期化処理
	SetDrawScreen(DX_SCREEN_BACK);	//裏画面に設定

	int x = 50;
	while(1){
		if(ProcessMessage() != 0){
			break;
		}
		ClearDrawScreen();
		x = 100;
		print(0, 0, 0, "TEST%d", x);

		ScreenFlip();

	}
    DxLib_End();    // DXライブラリ終了処理
    return 0;
}

/********** dxLibFunction.h **********/
void print(int, int, int, char *, ...);

void print(int x, int y, int color, char *str, ...){

    int Green = GetColor( 0, 255, 0 );      // 緑の色コードを取得
	DrawFormatString( x, y, Green, str, x);
}
としたのですが、結果は「TEST0」となってしまい「x」の値が渡っていませんでした。
展望としては、可変長引数を2つ3つ増やしても対応できるようにしたいです。

[1] 質問文
 [1.1] 自分が今行いたい事は何か
    DXライブラリの関数をまねて自作関数として置き換えたい
 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
    記載しました。
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
    結果は「TEST0」となる。
 [1.4] 今何がわからないのか、知りたいのか
    自作可変長関数の作り方。

[2] 環境  
 [2.1] OS : Windows7 64bit
 [2.2] コンパイラ名 : VC++ 2008EE

[3] その他
 ・どの程度C言語を理解しているか:基本情報レベル
 ・ライブラリを使っている場合は何を使っているか:DXライブラリ

ご享受ください。よろしくお願いします。

djann
記事: 27
登録日時: 12年前

Re: 可変長の自作関数を作りたいがうまくできない…

#2

投稿記事 by djann » 9年前

基本的に可変長引数の扱いは以下のようになります。

コード:

#include <stdio.h>
// 可変長引数を扱う為の型、関数、マクロ群.
#include <stdarg.h>


void variable( int num_args, ... )
{
	va_list args;	// これを経由して引数を扱う.
	va_start( args, num_args );	// args(va_list型)に可変長引数の情報を引き渡す.

	int n = va_arg( args, int );	// args(va_list)と型を渡して引数を取り出す.
	int m = va_arg( args, int );	// 次の引数が取れる.

	va_end( args );	// 使用終了のお知らせ
}

int main()
{
	variable( 2, 55, 66 );
}
これで、variable関数内でのnには55が、mには66が代入されます。


さて、問題はDrawFormatString()に引き渡す方法ですが・・・存在しません。argsを直接引き渡しても、それは可変長引数関数を呼び出した時とは別の形となっているからです。


ではどう解決するかですが、方法はいくつかあります。

1. DrawFormatString()には可変長引数を渡さない。
 これはprint関数内で文字列を先に作り、それで作られた文字列だけをDrawFormatString()に渡すという考え方です。これならば可変長引数をDrawFormatString()にまでもっていく必要はありません。
このような使い方を想定してか、C標準にはvsprintf()という関数が備わっています。

vsprintf()は、可変長引数の代わりにva_listを渡すことでsprintf()と同様の動きを行います。

コード:

#include <stdio.h>
// 可変長引数を扱う為の型、関数、マクロ群.
#include <stdarg.h>


void wrapper( char const *format, ... )
{
	va_list args;
	va_start( args, format );

	// このbufをDrawFormatString()に渡す考え.
	char buf[ 1024 ];
	vsprintf( buf, format, args );

	va_end( args );
}
この方法の難点は、最大文字列長がDrawFormatString()の仕様によらず固定されてしまうところでしょう。また、バッファオーバーフローに気を付けなくてはなりません。
※新しいVisual Studio等では「SDLチェック」というのに引っかかり使えないかもしれません。その際はエラーメッセージをよく読み、その通りに置き換えましょう。


2. C++の可変長引数「テンプレート」を使う。
 この方法は、Visual Studioならば2015が必須となりますし、C++を用いることになります。
C++は最近のバージョンアップでC++11というバージョンになりました(正式にはC++14までが存在します)。
こちらで新しく加えらえた「可変長引数テンプレート」という機能を使えば、DrawFormatString()へ直接可変長引数を渡すことが可能になります。

コード:

#include <stdio.h>


// ...Tが可変長引数テンプレートの指定.
// 引数のT ...argsは、Tを展開して各一つずつに引数を割り当てるという指定.
template <class ...T>
void wrapper( char const *format, T ...args )
{
	// args...は、割り当てられた一つ一つを展開するという指定.
	// このように直接渡せる.
	printf( format, args... );
}


int main()
{
	wrapper( "for %d\n", 5 );
}
このT... argsは0個以上となっているので、引数を渡さなかった時にも想定通り正常に動きます。
問題は先ほど書いた通り新しい機能で、Visual Studioが対応したのが2015からとなるのと、慣れない記法になってしまうということです。
また、テンプレートとなる関係上ヘッダに(使う場所で見える位置で)実装を記述する必要があります。


現在の開発環境はVC++ 2008とのことなので、基本的には1の方法をとると思いますが、環境を変えることも可能であれば検討の上、どちらかお好きな方を選び望む形で実装してください。

かずま

Re: 可変長の自作関数を作りたいがうまくできない…

#3

投稿記事 by かずま » 9年前

要するに、このように書けばよいのでは、ということですね。

コード:

#include <stdio.h>   // vsprintf
#include <stdarg.h>  // va_list, va_start, va_end

void print(int x, int y, int color, char *str, ...) {
    char s[1024];
    va_list ap;
    va_start(ap, str);
    vsprintf(s, str, ap);
    va_end(ap);
    int Green = GetColor(0, 255, 0);      // 緑の色コードを取得
    DrawString(x, y, s, Green);
}

ピーちゃん

Re: 可変長の自作関数を作りたいがうまくできない…

#4

投稿記事 by ピーちゃん » 9年前

スレット主です。
皆さんありがとうございます!

可変長・・・奥が深いですね。
でも皆さんのおかげで実装できました!
助かります^^

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 可変長の自作関数を作りたいがうまくできない…

#5

投稿記事 by みけCAT » 9年前

解決したら、解決チェックをお願いします。
解決チェックをするには、投稿画面の「送信」の右側にある「解決!」にチェックを入れた状態で返信を投稿してください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ピーちゃん

Re: 可変長の自作関数を作りたいがうまくできない…

#6

投稿記事 by ピーちゃん » 9年前

ありがとうございます。
解決しました。

閉鎖

“C言語何でも質問掲示板” へ戻る