-3

任意の数のパラメーターを受け入れる必要がある関数があるとしましょう。ここで重要なのは、プロトタイプを宣言せず、コードで呼び出されたときに関数を作成できるようにすることです。ランダムな数のparametersparametersを受け取るためにvoidへのポインターを使用していますが、これを行う場合、最初のパラメーターのメモリーアドレスへの参照のみが渡されるため、それが機能するためには、宣言する必要がありますコードで呼び出すのと同じ順序の変数:

unsigned char result=0;
unsigned char a=1; 
unsigned char b=2;
unsigned char c=3;

char main (void)
{
    for (;;)
    {
        result = function (&a, &b, &c);
        result = function (&c, &b, &a);
    }
}

function (void *vPointer)
{
    return (1);
}

また、呼び出しと一致しないため、型なしで関数を宣言しています(暗黙的にも宣言されています)。

ここでの結果は、関数で送信された最初のパラメーターへの参照です。したがって、最初の関数呼び出しで次のアドレスを指すと機能しますが、2番目の呼び出しでは、cへの参照とメモリが何であれ取得します。それが配置される場所の前に。

パラメータを並べ替える方法が正しい方法を参照していることを知っている人はいますか?または、関数内の不明な数のパラメーターを受け取る効果的な方法はありますか?

注:(...)使用しないでください。

4

4 に答える 4

2

すべてのC関数にはプロトタイプが必要です。これらは実際には必須ではありませんが、使用しない理由はありません(これらをサポートしていないANSI以前のコンパイラを使用している場合を除きます)。(ただし、この回答の下部を参照してください。)

可変数の引数を取る関数が必要な場合、そのプロトタイプはで終わる必要が, ...あり、関数自体は<stdarg.h>その引数を処理するメカニズムを使用する必要があります。(これには、定義されたタイプの引数が少なくとも1つ必要です。その引数は、次の引数のアンカーとして使用されます。)ここおよび他の場所で文書化されています。

これを入力しているときに、質問を「注:ライブラリ((...)など)は使用しないでください」で更新しました。<stdarg.h>は、自立型(埋め込み)のものを含む、すべての準拠C実装に必要な数少ないヘッダーの1つです。これは、関数を定義せず、型とマクロのみを定義するためです。C実装はそれをサポートする必要があります。そうでない場合は、準拠しているC実装ではないため、使用しているコンパイラを正確に通知するか、ドキュメントを読んで可変個引数関数または同等の機能を処理する方法を確認する必要があります。

, ...<stdarg.h>、(またはおそらく古い)を実際に使用できない場合は<varargs.h>、すべての使用に十分な固定数の引数を使用して関数を定義し、呼び出し元に追加のnullポインターを渡させることができます。

編集:

これは、コメントとチャットの新しい情報に基づく更新です。

printfOPには、何らかの理由で表記または。を使用しない、一部のTIマイクロコントローラに実装する宿題があります。問題のコンパイラは明らかにC89/C90を実装しているため、両方の機能をサポートしています。これは任意の制限です。, ...<stdarg.h>

この情報は問題になっているはずです。そのため、OPが更新するまで私はこの情報に反対票を投じています。

これを実現するための移植可能な方法はありません。これがまさに, ...標準言語の<stdarg.h>一部であり、標準ライブラリの一部である理由です。

おそらく最良のアプローチは、とを使用するプログラムを作成し, ...<stdarg.h>コンパイラーを呼び出して、プリプロセッサーの出力のみを表示し(さまざまなva_*マクロとva_listタイプを解決)、それを模倣することです。また、可変個引数関数と非可変個引数関数の呼び出し規約に互換性があることを前提とするか、コンパイラのドキュメントを使用して確認する必要があります。言い換えれば、この特定の実装が何をするのかを調べ、同様のホイールを再発明します。

(宿題のポイントは、標準的なテクニックがどれだけ優れているかを示すことだと思います。)

更新2:

私は、すべてのC関数にプロトタイプが必要であることを上に書きました。これは、実際にはこのルールのまれな例外である可能性があります。これらの呼び出しの少なくとも1つ:

printf("Hello\n");
printf("x = %d\n", 42);

printfで宣言されているか, ...(宿題の割り当てで禁止されている)、またはの目に見えるプロトタイプがない場合を除いて、準拠するコンパイラから診断を生成する必要がありますprintf。プロトタイプがない場合、少なくとも1つの呼び出しの動作が未定義になります(特定のコンパイラーによって定義されている場合でも、C標準で定義されていない動作)。

実際、宿題の要件を満たすには、ANSIC以前のコンパイラを使用しているふりをする必要があります。

于 2013-03-10T18:09:52.600 に答える
1

可変引数を持つ関数を使用する唯一の「クリーンな」方法は、可変個引数関数を使用することです。

#include <stdarg.h>

void myfun(int foo, ...) {
       va_list ap;
       va_start(foo, ap);
       // ...
       va_end(ap);
}

実際に期待する引数を知っていることを確認する必要があります(通常、最初の引数を使用して、期待する引数の数(および)を示します(例としては、int「nowcomearguments」またはformat-string 「%d%s:%s」のように、intと2つのchar *が来ることを意味します。または、最後の終了引数を使用します(たとえば、NULLに遭遇するまで引数を読み取ります)。

于 2013-03-10T18:13:32.563 に答える
0

可変長の配列を使用できます。

unsigned char result=0;
unsigned char a=1; 
unsigned char b=2;
unsigned char c=3;

function (int len, void *vPointer);

int main (void)
{
    for (;;)
    {
        unsigned char args[3];
        args[0] = a;
        args[1] = b;
        args[2] = c;
        result = function (3, args);
        args[0] = c;
        args[1] = b;
        args[2] = a;
        result = function (3, args);
    }
    return 0;
}

function (int len, void *vPointer)
{
    return (1);
}

ただし、代わりに標準的な方法、つまり可変個引数関数を使用することをお勧めします。

// jk

于 2013-03-10T18:23:51.580 に答える
0

構造を使用できます:-

typedef struct _Params {
   int m_a;
   int m_b;
   int m_c;
} Params;

そうすれば、パラメータを混同することはできません。あなたが必要とする最大までのより多くの文字と同じように。

于 2013-03-10T18:29:46.597 に答える