Что ... означает в списке аргументов в C? - PullRequest
32 голосов
/ 14 июля 2009

Я наткнулся на следующую сигнатуру функции и подумал, является ли это (многоточие или "...") полиморфизмом?

#include <fcntl.h>
int fcntl(int fd, int cmd, ... );

Заранее спасибо.

Ответы [ 14 ]

20 голосов
/ 14 июля 2009

Это список переменных .

15 голосов
/ 14 июля 2009

Это переменная функция . Подробнее см. stdarg.h .

11 голосов
/ 14 июля 2009

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

Значит ли это, что вы можете использовать это для реализации какой-то полиморфной функции? (То есть функция, которая выполняет некоторую операцию в зависимости от типа своих аргументов.)

номер

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

В случае, если функция, которая действительно должна принимать любое количество аргументов любого типа (то есть printf), типы аргументов передаются через строку формата. Это означает, что вызывающая сторона должна указывать типы, которые она будет передавать при каждом вызове, устраняя преимущество полиморфных функций (что вызывающая сторона также не должна знать типы).

Сравните:

// Ideal invocation
x = multiply(number_a, number_b)
y = multiply(matrix_a, matrix_b)

// Standard C invocation
x = multiply_number(number_a, number_b)
y = multiply_matrix(matrix_a, matrix_b)

// Simulated "polymorphism" with varargs
x = multiply(T_NUMBER, number_a, number_b)
y = multiply(T_MATRIX, matrix_a, matrix_b)

Вы должны указать тип, прежде чем функция varargs сможет сделать правильную вещь, так что это ничего не даст вам.

8 голосов
/ 14 июля 2009

Нет, это «многоточие», которое вы видите там, при условии, что вы ссылаетесь на часть ... декларации.

В основном это говорит о том, что эта функция принимает неизвестное количество аргументов после первых двух, которые там указаны.

Функция должна быть написана таким образом, чтобы она знала, чего ожидать, иначе получатся странные результаты.

Для других функций, которые поддерживают это, посмотрите на функцию printf и ее варианты.

6 голосов
/ 14 июля 2009

Поддерживает ли C полиморфизм? Нет, это не так.

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

Техника проста:

typedef struct {
    char * (*to_string)();
} Type;

#define OBJ_HEADER Type *ob_type

typedef struct {
    OBJ_HEADER;
}  Object; 

typedef struct {
    OBJ_HEADER;
    long ival;        
} Integer;

typedef struct {
    OBJ_HEADER;
    char *name;
    char *surname;
} Person;

Integer и Person получают объект Type с соответствующими указателями на функции (например, на такие функции, как integer_to_string и person_to_string).

Теперь просто объявите функцию, принимающую объект *:

void print(Object *obj) {
    printf("%s", obj->type->to_string());
}

теперь вы можете вызывать эту функцию как с целым числом, так и с персоной:

Integer *i = make_int(10);
print((Object *) i);

Person *p = make_person("dfa");
print((Object *) p);

EDIT

в качестве альтернативы вы можете объявить i и p как Object *; конечно, make_int и make_person выделят место для Integer и Person и выполнят соответствующее приведение:

Object * 
make_integer(long i) {
     Integer *ob = malloc(sizeof(Integer));
     ob->ob_type = &integer_type;
     ob->ival = i;
     return (Object *) ob;
}

NB. Сейчас я не могу скомпилировать эти примеры, пожалуйста, перепроверьте их.

Я наткнулся на следующую сигнатуру функции, и мне стало интересно, является ли это (многоточие или «...») полиморфизмом?

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

4 голосов
/ 14 июля 2009

Добавим к сказанному: C поддерживает полиморфизм другими способами. Например, возьмем функцию стандартной библиотеки qsort, которая сортирует данные произвольного типа.

Это можно сделать с помощью нетипизированных (void) указателей на данные. Также необходимо знать размер данных для сортировки (предоставляется через sizeof) и логику, которая сравнивает порядок объектов. Это достигается путем передачи указателя на функцию qsort.

Это яркий пример полиморфизма во время выполнения.

Существуют и другие способы реализации объектно-ориентированного поведения (в частности, вызовы виртуальных функций) путем ручного управления таблицами виртуальных функций. Это можно сделать, сохранив указатели функций в структурах и передав их вокруг. Многие API делают это, например WinAPI, который даже использует расширенные аспекты объектной ориентации, например, диспетчеризация вызовов базового класса (DefWindowProc, для имитации вызова виртуального метода базового класса).

2 голосов
/ 14 июля 2009

Я полагаю, вы имеете в виду многоточие (...)? Если это так, это означает, что последуют 0 или более параметров. Он называется varargs, определенный в stdarg.h

http://msdn.microsoft.com/en-us/library/kb57fad8.aspx

printf использует эту функцию. Без этого вы не сможете продолжать добавлять параметры в конец функции.

1 голос
/ 14 июля 2009

C поддерживает грубую форму полиморфизма. То есть тип, способный появляться и вести себя как другой тип. Он работает аналогично тому, как это было в C ++ под капотом (полагаясь на выравнивание памяти), но вы должны помочь компилятору с помощью приведения. Например. Вы можете определить структуру:

typedef struct {
     char forename[20];
     char surname[20];
     } Person;

А потом еще одна структура:

    typedef struct {
             char forename[20];
             char surname[20];
             float salary;
             char managername[20];
             } Employee;

Тогда

int main (int argc, int *argv)
{
    Employee Ben;
    setpersonname((Person *) &Ben);
}

void setpersonname(Person *person)
{
   strcpy((*person).Name,"Ben");
}

Приведенный выше пример показывает, что Сотрудник используется как Персона.

0 голосов
/ 14 июля 2009

Да, C Поддерживает ли полиморфизм

Код, который мы пишем на C ++, используя виртуальный для реализации полиморфизма, если сначала преобразовать его в код C с помощью компилятора (подробности можно найти здесь ).

Хорошо известно, что виртуальная функциональность в C ++ реализована с использованием указателей на функции.

0 голосов
/ 14 июля 2009

Вы можете написать код, который поддерживает полиморфное поведение в C, но ... (многоточие) не сильно поможет. Это для переменных аргументов функции.

Если вы хотите полиморфное поведение, вы можете использовать объединения и структуры для построения структуры данных, имеющей раздел «тип» и переменные поля в зависимости от типа. Вы также можете включить в структуры таблицы указателей функций. Пуф! Вы изобрели C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...