構造体の1つのフィールドの内容に基づいてリスト内の項目を検索するために、複数の関数が非常に似ているコードがあります。関数間の唯一の違いは、ルックアップが起きている構造体の型です。型を渡すことができれば、すべてのコードの重複を取り除くことができます。構造体型をC関数に渡す方法はありますか
私も同様に、これらの機能で何が起こっていくつかのミューテックスのロックがあることに気づいたので、私はこれを行うには
構造体の1つのフィールドの内容に基づいてリスト内の項目を検索するために、複数の関数が非常に似ているコードがあります。関数間の唯一の違いは、ルックアップが起きている構造体の型です。型を渡すことができれば、すべてのコードの重複を取り除くことができます。構造体型をC関数に渡す方法はありますか
私も同様に、これらの機能で何が起こっていくつかのミューテックスのロックがあることに気づいたので、私はこれを行うには
一つの方法は、最初のバイトとしてタイプフィールドを持つことである...私は放っておいかもしれないと思いますの構造。受信側の関数はこのバイトを調べ、見つかったものに基づいて正しい型にポインタをキャストします。別の方法は、型情報を、それを必要とする各関数に別個のパラメータとして渡すことです。
構造体はあらかじめ定義されたメモリブロックであるため、これを行うことができます。構造体にvoid *を渡すことができ、その型を定義する整数または何かを渡すことができます。
そこから、安全なすることは、データにアクセスする前にvoid *を適切な型のポインタに再作成することです。
void *にキャストしたときに型の安全性を失うので、非常に注意する必要があります。このようなときに実行時エラーが発生する可能性があります。
私は少し錆びていますが、functionパラメータの変数型としてvoid *ポインタを使用してみてください。次に、構造体のアドレスを関数に渡し、それをあなたが望むように使用します。
void foo(void* obj);
void main()
{
struct bla obj;
...
foo(&obj);
...
}
void foo(void* obj)
{
printf(obj -> x, "%s")
}
フィールドがこのような構造の同じ場所に配置されていることを確認した場合は、ポインタをフィールドにキャストするだけでフィールドに到達することができます。この技術は、多くの低レベルシステムライブラリで使用されています。 BSDソケット。
struct person {
int index;
};
struct clown {
int index;
char *hat;
};
/* we're not going to define a firetruck here */
struct firetruck;
struct fireman {
int index;
struct firetruck *truck;
};
int getindexof(struct person *who)
{
return who->index;
}
int main(int argc, char *argv[])
{
struct fireman sam;
/* somehow sam gets initialised */
sam.index = 5;
int index = getindexof((struct person *) &sam);
printf("Sam's index is %d\n", index);
return 0;
}
これを行うと型の安全性が失われますが、それは貴重な手法です。
[私は実際に上記のコードをテストし、さまざまなマイナーエラーを修正しました。コンパイラを持っているとずっと簡単です。 ]
構造パッキングが進行していないことに注意する必要がある。 構造体の最初のフィールドとして 'char'の型が異なる構造体の同じオフセットに格納されない可能性があります。 – itj
構造体のレイアウトは明示的に指定しない限り、プラットフォームABIによって指定されます。私はあなたがデフォルトで話しているような並べ替えやパッケージングを行うABIを持つことは実際には違法ではない(ISO C規格では禁じられている)が、それはかなり狂っているだろうと思う。私は、既存のソフトウェアの多くは、そのようなプラットフォーム上ではまったく動作しないと思います。 – tialaramex
これはパラメータ化されたマクロで行うことができますが、ほとんどのコーディングポリシーではそのことに惑わされます。
#include
#define getfield(s, name) ((s).name)
typedef struct{
int x;
}Bob;
typedef struct{
int y;
}Fred;
int main(int argc, char**argv){
Bob b;
b.x=6;
Fred f;
f.y=7;
printf("%d, %d\n", getfield(b, x), getfield(f, y));
}
短答:いいえ。しかし、そうするための独自のメソッドを作成することができます。つまり、そのような構造体を作成する方法の仕様を提供することができます。しかし、それは一般的に必要ではなく、努力する価値はありません。ちょうど参照渡し。 (callFuncWithInputThenOutput(input, &struct.output);
)
私はインスピレーションのためにCの標準関数qsort()とbsearch()を調べるべきだと思います。これらは、配列をソートし、あらかじめソートされた配列内のデータを検索する汎用コードです。彼らはどのようなタイプのデータ構造でも動作しますが、比較を行うヘルパー関数へのポインタを渡します。ヘルパー関数は構造体の詳細を知っているため、比較が正しく行われます。
実際には、検索を実行する必要があるため、必要なのはbsearch()ですが、データ構造をその場で構築する場合は、ソートされた構造体リスト。 (ソートされたリストを使うことができます。ヒープと比較して処理が遅くなる傾向があります。しかし、一般的なheap_search()関数とheap_insert()関数が必要です。このような関数はCで標準化されていません。
あなたがテストしたIDフィールドが、すべてのユーザーが共有するフィールドの共通の初期シーケンスの一部分である場合は、「ヒープサーチ」を試してみることはできません。構造体、そしてアクセスが動作することを労働組合の保証を使用して:あなたは不運だし、フィールドには、様々な構造体で異なるオフセットで表示された場合は
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int id;
long junk2;
} Bar;
typedef union
{
struct
{
int id;
} common;
Foo foo;
Bar bar;
} U;
int matches(const U *candidate, int wanted)
{
return candidate->common.id == wanted;
}
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 42, 0 };
U fu;
U bu;
fu.foo = f;
bu.bar = b;
puts(matches(&fu, 23) ? "true" : "false");
puts(matches(&bu, 42) ? "true" : "false");
return 0;
}
は、あなたがあなたの関数へのオフセットパラメータを追加することができます。次に、offsetofとラッパーマクロは、OPが要求したものをシミュレートします。 - コールサイトでstructの型を渡します。
#include <stddef.h>
#include <stdio.h>
typedef struct
{
int id;
int junk1;
} Foo;
typedef struct
{
int junk2;
int id;
} Bar;
int matches(const void* candidate, size_t idOffset, int wanted)
{
return *(int*)((const unsigned char*)candidate + idOffset) == wanted;
}
#define MATCHES(type, candidate, wanted) matches(candidate, offsetof(type, id), wanted)
int main(void)
{
Foo f = { 23, 0 };
Bar b = { 0, 42 };
puts(MATCHES(Foo, &f, 23) ? "true" : "false");
puts(MATCHES(Bar, &b, 42) ? "true" : "false");
return 0;
}
これはコンパイルできない方法はありません。あなたはそのようなvoidへのポインタを逆参照することはできません。 –
さて、公平になるためには、私はCで錆びていると言っていた;) –