如果 C 不支持函数重载,sem_open() 如何接受不同的参数大小?
How can sem_open() accept different argument sizes if function overloading isn't supported in C?
在学习共享进程信号量时,我注意到 sem_open() 具有两个函数原型:https://man7.org/linux/man-pages/man3/sem_open.3.html
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
如果 C 不支持函数重载,这怎么可能?
密钥可在联机帮助页(您链接的)中找到:
If O_CREAT
is specified in oflag
, then two additional arguments must be supplied.
这正是可变参数函数在 C 中的工作方式。可变参数函数具有固定数量的参数,每个参数具有 well-defined 类型,然后是 ...
,可以是任意数量的任何类型的参数,条件是被调用函数必须能够弄清楚每个参数的类型才能引用它。 printf
确实是最清楚的例子:格式字符串包含足够的信息 printf
可以确切知道期望的参数数量和类型。
请注意,不允许猜测。如果函数请求一个未提供的参数或请求与提供的参数不同的类型,它不会得到友好的错误指示或第二次机会。结果是未定义的行为:任何事情都可能发生,包括突然终止或无意义的结果。或者看似有道理但没有现实依据的结果。
与 open
一样,sem_open
使用它来允许仅在某些 well-defined 情况下需要的参数。如果调用可能会创建一个新的信号量(或文件,在 open
的情况下),它将请求额外的参数,假设它们是文档中指定的类型。
来电者有责任确保来电正确无误。请注意,由于可变参数没有声明的类型,因此编译器无法插入类型转换。因此,如果函数需要 double
,则不能使用 int
来调用它,这通常是可能的。此外,如果可变参数应该是 void*
,它必须是 void*
,而不是 0
(或 NULL
),因为从0 到空指针无法完成。
但是,允许调用者提供太多参数,或者相反,被调用函数不需要检查提供的每个参数。 (它不能跳过参数,但不需要到达列表的末尾。)
回想起来,这似乎是一个糟糕的语言特性。但这在当时看来是个好主意,现在不会消失。
C 没有重载。它 具有的是可变参数函数。
重载函数 是具有多种函数形式且每种形式的参数不同的函数。
可变参数函数 是 C 语言中可以接受可变数量参数的函数。这用省略号 (...) 表示,虽然这在手册页中并不明显,但如果您查看 sem_open() 的 source code,您可以看到它:
/* Open a named semaphore NAME with open flags OFLAG. */
extern sem_t *sem_open (const char *__name, int __oflag, ...) __THROW;
如您所见,在 __name 和 __oflag 之后,省略号表示 技术上 可以输入任意数量的参数。但是手册页指出的是 sem_open() 实际可以处理的变量。所以说真的,这不是两个具有不同逻辑的函数,而是一个可以处理两组不同参数的函数。
如果您想了解更多,可以阅读 this 有趣的文章,其中介绍了可变参数函数背后的一些历史。
在学习共享进程信号量时,我注意到 sem_open() 具有两个函数原型:https://man7.org/linux/man-pages/man3/sem_open.3.html
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
如果 C 不支持函数重载,这怎么可能?
密钥可在联机帮助页(您链接的)中找到:
If
O_CREAT
is specified inoflag
, then two additional arguments must be supplied.
这正是可变参数函数在 C 中的工作方式。可变参数函数具有固定数量的参数,每个参数具有 well-defined 类型,然后是 ...
,可以是任意数量的任何类型的参数,条件是被调用函数必须能够弄清楚每个参数的类型才能引用它。 printf
确实是最清楚的例子:格式字符串包含足够的信息 printf
可以确切知道期望的参数数量和类型。
请注意,不允许猜测。如果函数请求一个未提供的参数或请求与提供的参数不同的类型,它不会得到友好的错误指示或第二次机会。结果是未定义的行为:任何事情都可能发生,包括突然终止或无意义的结果。或者看似有道理但没有现实依据的结果。
与 open
一样,sem_open
使用它来允许仅在某些 well-defined 情况下需要的参数。如果调用可能会创建一个新的信号量(或文件,在 open
的情况下),它将请求额外的参数,假设它们是文档中指定的类型。
来电者有责任确保来电正确无误。请注意,由于可变参数没有声明的类型,因此编译器无法插入类型转换。因此,如果函数需要 double
,则不能使用 int
来调用它,这通常是可能的。此外,如果可变参数应该是 void*
,它必须是 void*
,而不是 0
(或 NULL
),因为从0 到空指针无法完成。
但是,允许调用者提供太多参数,或者相反,被调用函数不需要检查提供的每个参数。 (它不能跳过参数,但不需要到达列表的末尾。)
回想起来,这似乎是一个糟糕的语言特性。但这在当时看来是个好主意,现在不会消失。
C 没有重载。它 具有的是可变参数函数。
重载函数 是具有多种函数形式且每种形式的参数不同的函数。
可变参数函数 是 C 语言中可以接受可变数量参数的函数。这用省略号 (...) 表示,虽然这在手册页中并不明显,但如果您查看 sem_open() 的 source code,您可以看到它:
/* Open a named semaphore NAME with open flags OFLAG. */
extern sem_t *sem_open (const char *__name, int __oflag, ...) __THROW;
如您所见,在 __name 和 __oflag 之后,省略号表示 技术上 可以输入任意数量的参数。但是手册页指出的是 sem_open() 实际可以处理的变量。所以说真的,这不是两个具有不同逻辑的函数,而是一个可以处理两组不同参数的函数。
如果您想了解更多,可以阅读 this 有趣的文章,其中介绍了可变参数函数背后的一些历史。