2010-12-12 14 views
5

ジェネリックアレイを純粋なANSI-Cで複製することは可能ですか?純粋なANSI-C:ジェネリックアレイを作る

私は配列(現時点では浮動小数点用)と配列内のサイズや容量のような変数を保持するこの構造体を持っています。それは除いて、私は、「標準」のアレイが行うすべてのものなど、必要なときに動的配列のサイズを拡大し、これは私は、私はアイテムを追加/削除することができ、純粋なCの配列を作ることができストラクト使用

typedef struct _CustomArray 
{ 
    float* array; //the array in which the objects will be stored 
    int size; //the current size of the array 
    int capacity; //the max capacity of the array 
} CustomArray; 

Cのみで作られています。 これで、この構造体を初期化するときに保持する必要がある要素のデータ型を設定できるようにしたいと思います。現時点ではfloat型のデータ型しか格納できませんが、データ型/その他の構造体。しかし、これが可能かどうかは分かりません。

この時点では、この配列があることを確認するための機能:

CustomArray* CustomArray_Create(int initCapacity, /*type elementType*/) 
{ 
    CustomArray* customArray_ptr; //create pointer to point at the structure 
    float* internalArray = (float*)malloc(sizeof(float) * initCapacity); //create the internal array that holds the items 
    if(internalArray != NULL) 
    { 
     CustomArray customArray = { internalArray, 0, initCapacity }; //make the struct with the data 
     customArray_ptr = &customArray; //get the adress of the structure and assign it to the pointer 
     return customArray_ptr; //return the pointer 
    } 
    return NULL; 
} 

それはので、私はそのデータ型にメモリをmallocと動的配列で、与えられたデータ型としてそれをキャストすることができ、パラメータとしてデータ型を付与することができます?事前に

おかげで、

マーニックスバンライスワイク

+0

はピュアCであなたがそのようなデータ型を渡すことができるとは思いません。異種配列リスト(C#など)をサポートする言語を調べると、基本ではないデータ型、すなわちint型、float型などではなく、Classesでのみ動作します。Cはオブジェクト指向ではないため、この機能を得ることはほとんどありません。 –

+2

識別子をアンダースコアで開始しないでください。そのような名前は実装用に予約されています(compiler + libc)。アンダースコアと大文字を使用すると後者が重複します:これらの名前は、新しい言語機能が使用するものなので、どんなコンテキストでも予約されています(例えば、 '_Pragma'、' _Complex'、 '_Bool'など)。簡単な回避策は末尾のアンダースコアを使用することです。これはプレフィックスベースの名前空間でもうまくいきます。 – Christoph

+1

cでオブジェクト指向のビヘイビアをどのように構築できるかについては、サイト上で多くの質問があります。[Cのオブジェクト指向(http: /stackoverflow.com/q/415452/2509)と[Cでオブジェクト指向のコードを書くことができますか?](http://stackoverflow.com/q/351733/2509)などがあります。あなたは 'sizeof'とリンクで議論されている関数ポインタのメカニズムを賢明に使って、望む結果を達成することができますが、それは価値があるより多くの作業になります。 'qsort'と' bsearch'のインターフェースは妥協です。 – dmckee

答えて

8

あなたのコードでは、深刻な問題を抱えているよう...あなたはローカル変数(のCustomArray)のアドレスを返していると、機能はあなたがすることはできませんので、変数が破壊されていることを返すときに使用されていますポインタと共に使用してください。関数が返ってもメモリが利用できるように、その構造体もmallocする必要があります。

タイプにあなたがやや近いようなもので、たとえば...マクロを使用して取得できるパラメータ作りについて:あなたのことを、あなたはこのように

#include "customarray.h" 
DefArray(float); 
DefArray(double); 

void foo() 
{ 
    floatArray *fa = floatArrayCreate(100); 
    ... 
} 

注意をそれを使用することができます

#include <stdlib.h> 
#define DefArray(type) \ 
typedef struct T_##type##Array {\ 
    type *array; \ 
    int size, capacity; \ 
} type##Array; \ 
static type##Array *type##ArrayCreate(int capacity)\ 
{\ 
    type##Array *s = malloc(sizeof(type##Array));\ 
    if (!s) return NULL;\ 
    s->array = malloc(sizeof(type) * capacity);\ 
    if (!s->array) { free(s); return NULL; }\ 
    s->size=0; s->capacity = capacity;\ 
    return s;\ 
} 

をすべてのカスタム関数を定義するためにマクロを使用します。また、このアプローチは各モジュールのコードを複製することにも注意してください(大きな問題ではないと思いますが、C++を使用できない場合はターゲットプラットフォームがかなり小さいかもしれません)。やや複雑なアプローチでは、実装のために.hファイルと.cファイルを別々に生成することができます。

+0

すごくいいです、私はこれも確かに試してみます。これに感謝します。 –

+0

それは動作し、それは私に物事を行う完全な新しい方法を示しました。驚くばかり。 –

+3

Hehe ...メタプログラミングの世界へようこそ(コードを書くコードを書く)。 Cプリプロセッサはメタプログラミングのひどい弱い形ですが、C++テンプレート機械はちょっとだけ良いものです。本当の魔法のためには、外部ジェネレータ(Python/PerlなどのC/C++ジェネレータを書くのは簡単です)や、深刻なメタプログラミングが可能な他の言語(Lispなど)に移行する必要があります。 – 6502

2

少年が、これは本当にC++のための仕事のように聞こえます。

C言語で最も近いのは、型を渡すのではなくサイズ(sizeof(type))を渡すことだと思います。

関数をより汎用的にすることで、配列内の各項目のサイズが分かっている場合に必要な処理を行うことができます。これはbsearch()のような関数の働きです。

+0

ええと、ありがとう、私はC + +の仕事を知っています。それが可能かどうか疑問に思っていました。 :[悲しいことに、そうではありません。 –

+0

サイズを調べるだけでデータ型を前提にしても安全ですか? –

+0

Gunner:各アイテムがどれだけのメモリを使用しているかを前提にしても安全です。それはメモリの割り当てと移動に十分なはずです。唯一の問題は、データ型がポインタである場合です。その場合は、指されている項目もコピーする必要があります。しかし、すべての基本タイプに対して、このアプローチは完全に有効です。 –

2

これを達成する1つの方法は、いわゆるX-macrosを使用することです。

Hereは、この手法を使用した(おそらくバグの多い)ジェネリックベクターの実装です。

それを次に

// defining generic parameters 
#define PREFIX tv 
#define ITEM token 
#define NAME token_vector 
#include "vector.h" 

... 
token_vector tv = tv_new(100); 
*(tv.front) = some_token; 
tv_push_back(&tv, other_token); 
0

私は数年前にCでジェネリックプログラミングを使いこなしました。

基本的に、私はプリプロセッサを悪用しました。私は軽快に成功したと思います:最も重要ないくつかの一般的なデータ構造のいくつかのマクロ表記を行いました。

私は間違いなく(少なくとも自動的な方法で)マクロを再帰的に実行していました。つまり、配列の配列や配列のハッシュなどを作成していました。興味深いのはです。クレイジー Cプリプロセッサマクロのセマンティクス。

あなたが興味を持っている場合、ここでのコードだ:https://github.com/christianfriedl/CGenerics/blob/master/src/cgArray.h

関連する問題