3

私はCの初心者です。次のような3つの配列があるかどうか疑問に思っていました:

int a[] = {1, 2, 3}
char b[] = {'a', 'c', 'k'}
float c[] = {4.5, 5.8}

これらの配列のいずれかをこのように出力できる多態性関数を作成することは可能ですか?

prarray(a); prarray(b); prarray(c);

次の形式も使用できます。

prarray(a, int); prarray(b, char); prarray(c, float)

関数を解くことは可能void prarray(void *)ですか?誰にもアイデアはありますか?

4

6 に答える 6

6

最新の C 標準は C11 (C 2011) です。

キーワード_Generic (§6.5.1.1 ジェネリック選択、セクション §6.5 式の下) を提供して、あなたが求める種類のことを行います。

例えば、

#define prarray(A, len) _Generic((A), \
    int: prarray_int, \
    char: prarray_char, \
    float: prarray_float, \
    )(A, len)

void prarray_int( int* a, ptrdiff_t len ) { ... }
void prarray_char( char* a, ptrdiff_t len ) { ... }
void prarray_float( float* a, ptrdiff_t len ) { ... }

あとは、C11 コンパイラを入手するだけです。:-)

または、もう少し手動で C11 マクロの仕事を行います。実際には、型の名前を明示的なマクロ引数として渡し、##トークンの貼り付けを使用して関数名を生成します。

免責事項: コードはテストされていません (私は C11 コンパイラを持っていません)。また、1990 年代後半から C を使用していません。

于 2012-10-06T00:26:09.477 に答える
3

呼び出された関数がその仕事をできるように多くの支援を提供しないと、それを行うことはできません。標準 C ライブラリの 2 つの「多態性」関数を見てqsort()くださいbsearch()

void qsort(void *base, size_t nel, size_t width,
       int (*compar)(const void *, const void *));
void *bsearch(const void *key, const void *base, size_t nel,
       size_t width, int (*compar)(const void *, const void *));

およびファミリは、複数の型を処理するその他の関数ですprintf()scanf()

印刷配列関数には、次のものが必要になる可能性があります。

typedef int (*DataPrinter)(void *ctxt, void *data);
extern int prarray(void *base, size_t nel, size_t width,
                   DataPrinter pr_func, void *ctxt)

データ プリンター関数ポインターは、dataパラメーターで指定された 1 つの値を出力する役割を果たします。このctxt値は、データ プリンター機能が必要とする制御情報へのポインターです ( のように単純なFILE *場合もあれば、より複雑な場合もあります)。データ プリンター関数から返される値は、書き込まれた文字数です。から返される値prarray()は、書き込まれた文字の総数です。

もちろん、これは 1 次元配列に対してのみ機能します。2D または 3D 配列のサブセクションを印刷するには、より複雑なコードが必要です。改行などを気にする必要がある場合は、ctxt. または、この関数へのより複雑なインターフェイスを考案します。値セパレータを指定するために提供される唯一のメカニズムは、ctxt構造体を介するものであることに注意してください。これは動作します (または動作させることができます) が、あまりにもぎこちないかもしれません。


C2011 のソリューション_Genericは興味深いものですが、N 個の型に対して N 個の関数が必要で、それぞれが配列の出力を処理します。完全にくねくねすることはできません。私のソリューションには N+1 個の関数が必要ですが、そのうちの 1 つ (1 つ) だけが配列を処理します。N 個の関数はそれぞれ、指定された型の単一の値の出力を処理します。これは、指定された型の配列全体を出力するよりも簡単なプロセスです。もちろん、前述のように、関連するすべてのプラットフォームで C 2011 コンパイラが必要です。「頻繁に関連する」プラットフォームの少なくとも 1 つには、そのサプライヤーから C 1999 コンパイラが提供されていないため、そのプラットフォームで C 2011 を使用できるようになるまでにはしばらく時間がかかる可能性があります。

于 2012-10-06T00:16:34.877 に答える
2

同じ質問に対する私の2番目の回答。

もちろん、型情報を渡すと、データの処理方法を知る関数を作成できます。したがって、次の呼び出し規約を使用できます。

prarray(a, len, 'i'); prarray(b, len, 'c'); prarray(c, len, 'f');

「i」、「c」、および「f」には定数を使用する方がよいでしょうが、一般的な考え方は理解できます。関数定義は次のようになります。

void parray(void *genericPtr, int len, char typeCode) {
    if (typeCode == 'i') {
        int *intArray = (int*) genericPtr;
        printIntArray(intArray, len);
    }
    if (typeCode == 'c') {
        char *charArray = (char*) genericPtr;
        printString(charArray, len);
    }
    if (typeCode == 'f') {
        float *floatArray = (float*) genericPtr;
        printFloatArray(floatArray, len);
    }
}

邪悪で安全でない型キャストに注意してください。

于 2012-10-06T00:29:34.937 に答える
1

C11コンパイラなしで得られる最も近いものは、おそらくマクロです

#define prarray(array, format, length) ({\
    size_t i;\
    size_t _length = length ;
    for (i = 0; i < _length; i++) \
        printf(format ",", (array)[i]);\
})\

format を printf フォーマット文字列として呼び出します。たとえば"%c"、キャラクター、"%d"などint...

于 2012-10-06T00:50:51.597 に答える
0

c にはポリモーフィズムはありません。安全でない慣行なしでこれを行うには、配列とその長さを渡す 3 つの異なる関数が必要です。すなわち; void print_ints(int *a,int size); 等々。

于 2012-10-06T00:12:24.720 に答える
0

短い答えはノーです。

より長い答えは、さまざまな種類の値を含むことができる新しいデータ型を作成し、それらを出力する方法を知っている関数を作成できるということです。それはあなたが望むものを与えるでしょうが、あなたの値を定義することは構文的に厄介な場合があります.

率直に言って、人々が動的言語や OOP などを発明することを奨励したのは、まさにこの種の問題です。

私のCは本当に錆びていますが...

struct varyThing {
    char typeCode; // indicates what type of data it is.
    union valueUnion {
        long longValue;
        float floatValue;
        char string[32];
    } value;
};

構造全体は、型のサイズ、バイト アラインメント、およびその他のコンパイラの詳細に応じて、おそらく 34 バイトしか使用しません。

于 2012-10-06T00:19:40.603 に答える