Andy Stow Away による回答は、コンパイラの警告を修正しますが、2 番目の質問には回答しません。eddieantonio と Niklas R によって与えられたその回答へのコメントは、私の 2 番目の質問に答えますが、コンパイラの警告を修正しません。だから私はそれらを1つの答えにまとめています。
C はオブジェクト指向ではなく、C でオブジェクト指向の設計をエミュレートしようとすると、通常、スタイルが悪くなります。私の例のように、構造体へのポインターを使用して呼び出すことができるように、構造体で呼び出されるメソッドを複製することも例外ではありません。(率直に言って、これは DRY に違反しています。) 構造体の関数ポインターは、ポリモーフィズムに役立ちます。たとえば、要素の線形シーケンスの汎用コンテナーを表す struct ベクトルがある場合、関数ポインターである comparison_func メンバーを格納して、ベクトルの並べ替えと検索を行うと便利な場合があります。ベクトルの各インスタンスは、異なる比較関数を使用できます。ただし、構造体自体を操作する関数の場合は、構造体で重複しない単一の別個の関数を使用する方が適切です。
これにより、何が正しいかの答えがより複雑になります。上記の例をコンパイルする正しい方法は何ですか? 上記の例を再フォーマットして、スタイルを良くする方法はありますか? それとも、C プログラマーが行う方法で関数ポインターを使用する構造体の例は何ですか? 私の質問を定式化する際に、私は私の質問が間違っているという答えを期待していませんでした. 完全を期すために、質問に対する各回答の例を示します。
コンパイラ警告の修正
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*, int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
スタイルの再フォーマット
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
};
void my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
my_struct_set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
構造体での関数ポインタの使用方法のデモンストレーション
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct
{
void* data;
int (*compare_func)(const void*, const void*);
};
int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
return m->compare_func(m->data, comparable);
}
struct my_struct* my_struct_create(void* initial_data,
int (*compare_func)(const void*, const void*))
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = initial_data;
result->compare_func = compare_func;
return result;
}
int int_compare(const void* a_pointer, const void* b_pointer)
{
return *(int*)a_pointer - *(int*) b_pointer;
}
int string_compare(const void* a_pointer, const void* b_pointer)
{
return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}
int main(int argc, const char* argv[])
{
int int_data = 42;
struct my_struct* int_comparator =
my_struct_create(&int_data, int_compare);
char* string_data = "Hello world";
struct my_struct* string_comparator =
my_struct_create(&string_data, string_compare);
int int_comparable = 42;
if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
{
printf("The two ints are equal.\n");
}
char* string_comparable = "Goodbye world";
if (my_struct_compare_to_data(string_comparator,
&string_comparable) > 0)
{
printf("The first string comes after the second.\n");
}
free(int_comparator);
free(string_comparator);
return 0;
}