......在C的参数列表中意味着什么?

时间:2009-07-14 09:00:47

标签: c

我遇到了以下函数签名,我想知道这个(省略号,或"...")是否是某种多态性?

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

提前致谢。

14 个答案:

答案 0 :(得分:20)

答案 1 :(得分:15)

那是variadic function。有关详细信息,请参阅stdarg.h

答案 2 :(得分:11)

...表示您可以将任意数量的参数传递给此函数,正如其他评论者已经提到的那样。由于未键入可选参数,因此编译器无法检查类型,您可以从技术上传递任何类型的任何参数。

这是否意味着您可以使用它来实现某种多态函数? (即,一个基于其参数类型执行某些操作的函数。)

没有

你不能这样做的原因是因为你不能在运行时检查传入的参数的类型。变量参数列表中的函数读取应该已经知道它将接收的可选参数的类型。

如果一个函数真的应该能够接受任何类型的任意数量的参数(即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函数做正确的事情之前指定类型,这样你就什么也得不到了。

答案 3 :(得分:8)

不,这是你在那里看到的“省略号”,假设你指的是宣言的...部分。

基本上它说这个函数在前两个参数之后接受了未知数量的参数。

该函数必须以一种知道会发生什么的方式编写,否则会产生奇怪的结果。

对于支持此功能的其他功能,请查看printf函数及其变体。

答案 4 :(得分:6)

  

C是否支持多态?   不,它没有。

然而,有几个库,例如Python C API,使用结构和指针实现多态的粗略变体。请注意,在大多数情况下,编译器无法执行适当的类型检查。

tecnhique很简单:

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等函数)。

现在只声明一个接受Object *的函数:

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

现在你可以用Integer和Person调用这个函数:

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

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

修改

或者你可以将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;
}

注意:我现在无法编译这些示例,请仔细检查它们。

  

我遇到了以下函数签名,我想知道这个(省略号或“......”)是否是某种多态性?

是的,它是原始形式的多态。只有一个功能签名,您可以传递各种结构。但是,编译器无法帮助您检测类型错误。

答案 5 :(得分:4)

添加到已经说过的内容:C通过其他方式支持多态性。例如,采用标准库qsort函数对任意类型的数据进行排序。

可以通过指向数据的无类型(void)指针来实现。它还需要知道要排序的数据的大小(通过sizeof提供)以及比较对象顺序的逻辑。这是通过将函数指针传递给qsort函数来完成的。

这是运行时多态性的一个主要示例。

通过手动管理虚拟功能表,还有其他方法可以实现面向对象的行为(特别是虚函数调用)。这可以通过在结构中存储函数指针并传递它们来完成。许多API这样做,例如WinAPI,甚至使用面向对象的高级方面,例如基类调用调度(DefWindowProc,用于模拟调用基类的虚方法。)

答案 6 :(得分:2)

我假设你指的是省略号(...)?如果是,则表示将跟随0个或更多个参数。它被称为varargs,在stdarg.h中定义

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

printf使用此功能。没有它,你将无法继续在函数末尾添加参数。

答案 7 :(得分:1)

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

上面的示例显示了Employee被用作Person。

答案 8 :(得分:0)

不,这是一个带有可变数量参数的函数。

答案 9 :(得分:0)

这不是技术上的多态性。 fcntl采用可变数量的参数&amp;这就是...类似于printf函数的原因。

答案 10 :(得分:0)

C既不支持函数重载 - 这是一种基于编译时类型的 ad-hoc多态 - 也不支持多次调度(即基于运行时类型的重载)。

要在C中模拟函数重载,您必须创建多个不同命名的函数。函数名称通常包含类型信息,例如字符为fputc(),字符串为fputs()

可以使用可变参数宏实现多个分派。同样,程序员的工作是提供类型信息,但这次是通过一个额外的参数,它将在运行时进行评估 - 与上面给出的方法的编译时函数名称形成对比。 printf()系列函数可能不是多次调度的最佳示例,但我现在想不出更好的函数。

使用指针代替可变参数函数或在结构中包装值以提供类型注释的多分派的其他方法存在。

答案 11 :(得分:0)

标准库中的printf声明是

int printf(const char*, ...); 

想一想。

答案 12 :(得分:0)

您可以在C中编写支持多态行为的代码,但是......(省略号)不会有太大帮助。这是针对函数的变量参数。

如果您需要多态行为,可以使用,联合和结构来构造具有“类型”部分和可变字段的数据结构,具体取决于类型。您还可以在结构中包含函数指针表。噗!你发明了C ++。

答案 13 :(得分:-5)

是C支持多态性

我们在C ++中使用virtual编写的代码来实现多态 如果首先由编译器转换为C代码(可以找到详细信息here)。

众所周知,C ++中的虚拟功能是使用函数指针实现的。