2013-06-11 2 views
49

Im пытается создать функцию внутри структуры, до сих пор у меня есть этот код:C - функция внутри структуры

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(); 

} 

Ошибка: client.h: 24: 2: ошибка: ожидается «: ',', ','; ','} 'или' атрибут 'перед' {'токеном.

Какой правильный способ сделать это?

+9

Вы не можете иметь функции в структурах в C; вы можете попытаться примерно имитировать это, указав указатели на функции. – Fingolfin

+1

Являются ли функции указателями приемлемой заменой? http://stackoverflow.com/a/840703/635678 –

ответ

71

Это не может быть сделано непосредственно, но вы можете эмулировать то же самое, используя указатели на функции и явно прохождение «этого» параметра:

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); 

} 

Оказывается, однако, что это не очень дорого вы покупаете. Таким образом, вы не увидите много API C, реализованных в этом стиле, поскольку вы можете просто вызвать свою внешнюю функцию и передать экземпляр.

+1

Большое спасибо, сэр – amanuel2

+1

X11 API делает что-то вроде этого. См. [XImage] (https://en.wikipedia.org/wiki/XImage). – Hydranix

+0

код, который находится под Windows API, полон этим. Технически «класс окна» представляет собой структуру с двумя указателями функций обратного вызова и с открытым концом (для этих «данных спецификаций класса окна», которые вы можете предоставить при регистрации) – Swift

10

Это будет работать только на C++. Функции в структурах не являются отличительными чертами C.

То же самое касается вашего клиента.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); 

} 
+0

Это проект uni, и я должен использовать C. Есть ли способ, который я могу выполнить, что я хочу в C? – xRed

+0

Просто переместите эту функцию за пределы структуры и заставите ее принять указатель на ваш экземпляр. –

+0

Объект client.AddClient() не будет возможен без сложной магии (см. Другой ответ). – QSQ

18

Как отмечали другие, встроенные указатели функций непосредственно внутри вашей структуры обычно зарезервированы для специальных целей, таких как функция обратного вызова.

Что вы, вероятно, хотите, это нечто большее, чем таблица виртуальных методов.

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 имеют такой слой.

+0

См. Также [динамическая отправка] (http://stackoverflow.com/a/17622474/315052). – jxh

4

Как насчет этого?

#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; 
} 
+0

«Маленькое» решение JavaScrip –

0

Вы пытаетесь сгруппировать код в соответствии со структурой. Сгруппировка по файлам. Вы помещаете все функции и внутренние переменные в заголовок или заголовок и файл «.o» объекта, скомпилированный из исходного файла c.

Нет необходимости повторно изобретать объектную ориентацию с нуля для программы на C, которая не является объектно-ориентированным языком.

Я видел это раньше. Странная вещь. У некоторых кодеров есть отвращение к передаче объекта, который они хотят изменить, в функцию для его изменения, хотя это стандартный способ сделать это.

Я обвиняю C++, потому что скрывал тот факт, что объект класса всегда является первым параметром в функции-члене, но он скрыт. Таким образом, похоже, что он не передает объект в функцию, даже если это так.

Client.addClient(Client& c); // addClient first parameter is actually 
          // "this", a pointer to the Client object. 

C гибкий и может принимать передаточные предметы по ссылке.

Функция C часто возвращает только статусный байт или int, и это часто игнорируется. В вашем случае правильная форма может быть

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

Смежные вопросы