在C语言中的函数重载

27

今天我查看了open()的man页,发现这个函数是“重载”的:

   int open(const char *pathname, int flags);
   int open(const char *pathname, int flags, mode_t mode);
我没想到在 C 语言中这是可能的。实现它的“技巧”是什么? 稍后编辑: 所以这并不是真正的重载,因为使用可变参数时,只能提供相同类型的多个参数。那么,在幕后,mode_t 是 int 吗?

mode_t确实是一个整数,但您可以提供不同类型的参数,只要您知道如何解释它们。 printf函数族就是这样做的,使用格式字符串来知道如何解释其额外的参数,即使它们具有不同的类型。下面的答案中有一些示例,可能会澄清这一点。 - Eli Courtwright
@Eli 谢谢,我一定是把它和Java混淆了。 - Andrei Ciobanu
这样的函数被称为可变参数函数。 - Chris
5个回答

37

它正在使用可变参数。这些声明仅出现在man页面中,因为这2种方法是您应该调用open()的唯一方式。实际的C函数将被声明为例如:

int open(const char *pathname,int flags,...);

使用可变参数时,参数的类型不需要相同。 printf 就是一个明显的例子。

在使用 open() 函数时,如果 'flags' 参数包含 O_CREAT 标志,则第一个可变参数必须为 mode_t,因为 open() 的实现希望它是 mode_t 类型(在幕后可能是 unsigned int 或 unsigned long 类型,但这与可变参数无关)。


12

C语言确实可以编写具有可变数量参数的函数,例如printf

话虽如此,在C语言中没有可靠的、跨平台的方法来编写只带有2或3个参数的函数;通常你必须像这样做:

some_function(5, 6, 7, NULL);
some_function(5, 6, 8, 2, 5, NULL);

换句话说,你必须有一个终止的“sentinal”参数。或者,你可以在早期的参数中以某种方式包含参数的数量,例如:
another_func(2, "hello", "world");
another_func(3, "goodbye", "cruel", "world");
printf系列函数采用这种方法;第一个格式参数包含所需的额外参数数量;例如,使用printf("%f %f", 5.6, 7.11),您知道必须有2个浮点参数。但是,在用户定义的库函数中,这可能会有些不安全,因为如果您说my_printf("%s %f %f %f %s", 5.6),那么您可能会得到segfault或更糟的情况。幸运的是,大多数C编译器将在编译时检查对printf的调用,以避免出现此类问题。
open的情况下,该函数被声明为具有可变参数,并且仅在设置了O_CREAT时才检查第三个参数。因此,这就是它“安全”地确定第三个参数是否存在的方式。我用引号括起来的“安全”,因为从技术上讲,open无法在运行时知道实际传递了多少个参数。例如,以下调用将编译而不会出现任何错误或警告:
open("foo.txt", 5, "not an integer", 7);    // extra and invalid parameters
open("bar.txt", O_CREAT);                   // third parameter is missing

2
如果 some_function() 的参数是 int 类型,就不应该以 NULL 结尾,因为在数值上下文中 NULL 只是 0。NULL 终止符最适用于指针参数。 - Chris Lutz
@Chris:说得好,我通常使用NULL作为终止符,无论数据类型如何,但你说得对,这可能会让人感到困惑,特别是对于那些不知道0和NULL是相同的人来说,因为他们可能认为可以编写类似some_func(3, 2, 1, 0, -1, NULL)的代码,而实际上这将导致0充当终止参数。 - Eli Courtwright
2
最近版本的gcc和glibc头文件一起编译你的最后两个示例会产生警告。 - caf

6
O_CREAT 在标志中时,必须指定模式,否则将被忽略。 extern int open (__const char *__file, int __oflag, ...) 使用可变参数列表,并且仅在 __oflag 包含 O_CREAT 时才加载模式变量参数。

3

您可以使用变量参数列表和 ... 来模拟它。

int function(int x, ...);

3
非常简短的答案 - 可变参数(varargs)

1
请勿对正确答案进行负面评价,简洁是一种美德。 - KevinDTimm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接