我正在尝试在
struct
内分配一个函数,到目前为止我有这个代码:
typedef struct client_t client_t, *pno;
struct client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
pno next;
pno AddClient()
{
/* code */
}
};
int main()
{
client_t client;
// code ..
client.AddClient();
}
**Error**: *client.h:24:2: error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘{’ token.*
正确的做法是什么?
它不能直接完成,但您可以使用函数指针并显式传递“this”参数来模拟相同的事情:
typedef struct client_t client_t, *pno;
struct client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
pno next;
pno (*AddClient)(client_t *);
};
pno client_t_AddClient(client_t *self) { /* code */ }
int main()
{
client_t client;
client.AddClient = client_t_AddClient; // probably really done in some init fn
//code ..
client.AddClient(&client);
}
然而,事实证明,这样做并不能真正给你带来很多好处。因此,您不会看到许多以这种风格实现的 C API,因为您也可以只调用外部函数并传递实例。
正如其他人所指出的,直接在结构中嵌入函数指针通常是为了特殊目的而保留的,例如回调函数。
您可能想要的是更像虚拟方法表的东西。
typedef struct client_ops_t client_ops_t;
typedef struct client_t client_t, *pno;
struct client_t {
/* ... */
client_ops_t *ops;
};
struct client_ops_t {
pno (*AddClient)(client_t *);
pno (*RemoveClient)(client_t *);
};
pno AddClient (client_t *client) { return client->ops->AddClient(client); }
pno RemoveClient (client_t *client) { return client->ops->RemoveClient(client); }
现在,添加更多操作不会改变
client_t
结构的大小。现在,这种灵活性仅在您需要定义多种客户端,或者希望允许 client_t
界面的用户能够增强操作行为方式时才有用。
这种结构在实际代码中确实出现过。 OpenSSL BIO 层看起来与此类似,UNIX 设备驱动程序接口也有类似的层。
这个怎么样?
#include <stdio.h>
typedef struct hello {
int (*someFunction)();
} hello;
int foo() {
return 0;
}
hello Hello() {
struct hello aHello;
aHello.someFunction = &foo;
return aHello;
}
int main()
{
struct hello aHello = Hello();
printf("Print hello: %d\n", aHello.someFunction());
return 0;
}
这只适用于 C++。 结构体中的函数不是 C 的特性。
你的 client.AddClient() 也是如此; call ...这是对成员函数的调用,这是面向对象编程,即C++。
将您的源代码转换为 .cpp 文件并确保进行相应的编译。
如果您需要坚持使用 C,下面的代码(某种程度上)是等效的:
typedef struct client_t client_t, *pno;
struct client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
pno next;
};
pno AddClient(pno *pclient)
{
/* code */
}
int main()
{
client_t client;
//code ..
AddClient(client);
}
您正在尝试根据结构对代码进行分组。 C 分组是按文件进行的。 您将所有函数和内部变量放在标题中或 从 c 源文件编译的头文件和对象“.o”文件。
没有必要从头开始重新发明面向对象 对于 C 程序,它不是面向对象的语言。
我以前见过这个。 这是一件奇怪的事情。编码员(其中一些人)不愿意将他们想要更改的对象传递给函数来更改它,即使这是这样做的标准方法。
我责怪C++,因为它隐藏了类对象始终是成员函数中的第一个参数的事实,但它是隐藏的。所以看起来它没有将对象传递到函数中,即使它是这样。
Client.addClient(Client& c); // addClient first parameter is actually
// "this", a pointer to the Client object.
C 很灵活,可以通过引用来获取传递的东西。
C 函数通常仅返回状态字节或 int,并且经常被忽略。 在你的情况下,正确的形式可能是
/* add client to struct, return 0 on success */
err = addClient( container_t cnt, client_t c);
if ( err != 0 )
{
fprintf(stderr, "could not add client (%d) \n", err );
}
addClient 将位于 Client.h 或 Client.c 中
假设您有以下结构:
struct Object {
int field;
}
在 C 中,没有好方法来编写
object.Add(1)
并让 Add
使用/更改 object
的字段。您有两个选择:
a) 放弃编写
object.Add(1)
的愿望,转而编写惯用的 C 代码。试图找到一种使用一些技巧在 C 中编写 object.Add(1)
的方法只会使代码变得更复杂,更容易出现错误,并且不值得。
在 C 中执行此操作的等效方法是让一个单独的函数接受指向对象的指针:
void Add(struct Object *object, int amount) {
object->field += amount;
}
并按如下方式调用该函数:
struct Object object;
Add(&object, 1);
b) 使用另一种编程语言。例如,在C++中,您可以定义一个方法:
struct Object {
int field;
void Add(int amount) {
field += amount;
}
}
并在您的代码中使用它:
Object object;
object.add(1);
C++ 编译器将使它代表您工作。事实上,只要不涉及继承,C++代码就等价于(a)中提到的函数定义及其调用。
您刚刚发明了 C++。将一些变量与一些函数组合在一起的想法是 C++ 的想法之一。将
struct
重命名为 class
,您就快完成了。
class client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
client_t *next;
public:
void AddClient()
{
/* code */
}
};
int main()
{
client_t client;
// code ..
client.AddClient();
}
(抱歉回答11年前的问题)
您可以将结构体指针作为函数参数传递给函数。 这称为通过引用传递。
如果您修改该指针内的某些内容,其他内容将被更新。 尝试这样:
typedef struct client_t client_t, *pno;
struct client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
pno next;
};
pno AddClient(client_t *client)
{
/* this will change the original client value */
client.password = "secret";
}
int main()
{
client_t client;
//code ..
AddClient(&client);
}