2009-07-14 120 views
32

我遇到了下面的函数签名,我想知道这个(省略号或"...")是否是某种多态性?在C中的参数列表中是什么意思?

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

在此先感谢。

+4

公平的问题。 +1。有些人仍然认为,简单的问题并不适合,尽管权力表明他们是这样。 – paxdiablo 2009-07-14 09:12:48

+0

我建议将问题的标题改为“什么是省略号(...)C:“ – 2009-07-14 09:26:18

+0

@Hosam:是的,它不是真的关于多态性...标题改变了。 – 2009-07-14 10:05:03

回答

8

不,那是“省略号”你看到没有,假设你指的是声明的...一部分。

基本上它说这个函数在指定的前两个参数后面有一个未知数量的参数。

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

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

+1

此外,参数也有一个未知类型。所有你在函数中得到的是一个指向第一个参数的指针,你必须把它变成有用的东西 – 2009-07-14 11:08:58

2

我假设你指的是省略号(...)?如果是这样,则表示将会有0个或更多参数。这就是所谓的可变参数,在STDARG.H定义

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

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

0

不,它是一个函数,它使用可变数量的参数。

0

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

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) 

您必须指定可变参数函数可以做正确的事情之前的类型,所以这次获得你什么。

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; 

整数和人获得具有适当的函数指针的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); 

编辑

或者你也可以将i和p声明为Object *;当然make_int和make_person将为整数和人员分配空间,并做相应的转换:

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

注:我不能编译这些例子分辩现在,请他们双检。

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

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

0

C既不支持函数重载 - 这是一种特设多态性基于编译时类型 - 也不支持多重分派(即基于运行时类型的重载)。

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

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

存在使用指针而不是可变参数或包装结构中的值来提供类型注释的多重分派的其他方法。

4

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

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

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

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

1

标准库的printf的声明

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

试想一下。

0

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

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

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

上面的例子显示雇员被用作人。

-4

是c不支持多态

的代码,我们在C++编写使用虚拟实现多态性 如果先转换为通过编译器的C代码(一个可以找到细节here)。

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