2013-07-16 19 views
5

私は比較的Cプログラミング言語が新しく、様々な種類のデータをパラメータとして受け入れることができる関数を作成する方法を理解しようとしています。この関数は、文字配列または整数配列の要素数を数えて返します。私はすでにこれを行う2つの別個の機能を持っていますが、私は本当に両方のタスクに1つの機能を使用できるようにしたいと思います。 Cでこれを行う方法はありますか?異なるデータ型のパラメータを受け入れるC関数を作成します。

ありがとうございます!

答えて

5

Cで標準的な関数のオーバーロードはありません(テンプレートもあります)が、おそらくprintfのような関数(またはvariadic functions)を調べて、必要な処理を行うことができます。何かがあれば、柔軟なパラメータリストが可能になります。

可変サイズ整数配列をとる関数の例はhereです。

おそらく、あなたは次の方法で使用しているvoid iterate(const char* format, ...);ような関数のシグネチャを持つことができます:

iterate("char", some_char_array); // for char arrays/strings 

それとも

iterate("int", some_int_array); // for integer arrays 

Aniketはしかし良い点を作り、どのように要素を数えません整数配列で? int配列を引数として渡す場合、配列の要素を数える目的を破るサイズを渡す必要があります(すでに知っているように、つまりサイズ)。

サイズはわからないものの、配列にターミネーター値(-1など)があります。

私は、上記の前提を念頭に置いて必要なことをやや早くやり遂げました。

#include <stdarg.h> 
#include <stdio.h> 
#include <string.h> 

int iterate(const char* format, ...) 
{ 
    va_list ap; 
    va_start(ap, format); 

    if (strcmp(format, "char") == 0) 
    { 
     char* array = va_arg(ap, char*); 

     return strlen(array); 
    } 
    else if (strcmp(format, "int") == 0) 
    { 
     int j = -1; 
     int* int_array = va_arg(ap, int*); 
     while (int_array[++j] != -1) 
        ;  
     return j; 
    } 
    return 0; 
} 

int main() 
{ 
    printf("%d\n", iterate("char", "abcdef")); 
    int arr[] = {5, 4, 3, 2, 1, 0, -1}; 
    printf("%d\n", iterate("int", arr)); 

    return 0; 
} 

この版画:いずれの場合も

$ ./a.out 
6 
6 
+0

int sizeは何ですか? –

+0

アレイのサイズは?私はこれが明確でないように見えるので、これを明らかにするでしょう。 – Nobilis

+0

もし彼が手前の配列のサイズを知っていたら、どうしてこのようなスーパー関数を使って型を自動的に推測し、配列の長さを計算する適切な関数を呼び出すのでしょうか? :-) –

1

関数の引数をvoid *の型にする必要があります。こうすることで、さまざまな種類のデータを渡して、必要なデータに型キャストすることができます。しかし、void*が指し示すタイプを正確に '推測'する保証された方法がないので、注意する必要があります。

2

は、あなたが呼び出すために機能するCコンパイラを伝えるために、型推論システムのいくつかの並べ替えが必要になります。つまり、自分の「スーパーファンクション」へのパラメータとして送るかもしれないアレイのタイプを、事前に知っておく必要があります。

Cには、実行時にデータの種類を反映させることのできる「自動型推論」はありません。このためには、独自のランタイム環境を作成する必要があります。これを行うには

Aやや平凡なハック方法:

#include <stdio.h> 

size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes) 
{ 
    return sizeOfTheArrayInBytes/sizeOfOneElementInArray; 
} 
int main(int argc, char *argv[]) 
{ 
    char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'}; 
    int iArr[5] = {10,20,30,40,50}; 
    printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)), 
                   GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr))); 
    return 0; 
} 
+0

C11には '_Generic'があります。 – jxh

2

はそれでは、あなたの二つの機能を想定してみましょうがsizeof_char_arraysizeof_int_arrayと呼ばれています。C11では

、あなたは比較的簡単なマクロでやりたいようになる「一般的な選択」と呼ばれる新しい機能があります:

#define sizeof_array(X) \ 
    _Generic (*(X), \ 
       char: sizeof_char_array, \ 
       default: sizeof_int_array) (X) 

(私もテストにC11の実装を持っていません。

C11以前は、定期的に名前を付けられた機能を使用してマクロを実行することがありました。あなたは、マクロ引数のヒントに応じて、1つの機能または他のを呼び出すマクロを定義することができます。

#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x) 

int a[] = { 1, 2, 3, 4, -1 }; 
char b[] = "abc"; 

sizeof_array(int, a); /* macro expands to sizeof_int_array(a) */ 
sizeof_array(char, b); /* macro expands to sizeof_char_array(b) */ 

入力引数が真の配列である場合は、直接そのサイズを計算するためにマクロを使用することができます。

アレイの場合
#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0)) 

、以下の式が真である:

(void *)arr == &arr 

アレイのアドレスは、その最初の要素のアドレスとしてメモリ内の同じ位置を有するからです。

したがって、マクロはsizeof(arr)/sizeof(arr[0])を計算します。 sizeof演算子は引数のバイト数を報告するので、計算式の結果は配列の要素数になります。しかし、センチネルを使用して長さを計算する場合、ARRAY_SZマクロは、センチネルの配列を横切って見つかった長さよりも少なくとも1サイズ大きいサイズになります。

引数が配列でない場合、式は0除算例外になります。

+0

厳密に言えば: - P、OPは、ポインタが保持するデータのタイプに応じて、1つの関数から2つの異なる関数を呼び出す必要があります。 –

+0

だから、彼はある種の型推論システムを望んでいると思います。これについて私の考えだけ。 –

+0

@Aniket:それは関数に渡された後に配列の長さを推論することができないので、それはあまり意味がありません。配列の長さは関数に渡す必要があります(推量がセンチネル値で行われない限り)。 – jxh

2

答えは非常に簡単です。この作業には関数が必要です。このコードを試してみてください。

#define len(array) sizeof(array)/sizeof(array[0]) 

それだけです。

関連する問題