unix 的 man page显示了下面的open函数原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
它提示我们有两个版本的open函数, 你用两个参数调用它就调用两个参数的版
本, 给三个参数就调用三个参数的版本, 似乎很神奇.
这样的写法给人以假象.
K&R的bible 里8.3节讲UNIX接口的OPEN函数, 也没有提到这点:
===========================
To open an existing file for reading,
fd = open(name, O_RDONLY,0);
The perms argument is always zero for the uses of open that we will discuss.
===========================
实际上在这种情况下第三个参数是多余但无害的.
问题是, 这是C语言, 它没有C++的overload机制, 一个函数的签名是不包括参
数部分的, 编译器如何实现? 编译器对名为open的函数特别对待? 可能性不大
.
曾经有段时间我还肤浅地对人说过, 其实C语言中就有了C++的overload机制的
原型, UNIX的open 系统调用就有两个参数的版本.
然而, 这只是一种假象.
open的真正原型是:
extern int open (__const char *__file, int __oflag, ...)
它是变参函数.
当 __oflag中有 O_CREAT时, 才会需要后面的一个参数. 然而open的实现却不
象printf 那样表现出可传递参数在实用中的多变性. 它只有两种真正有用的
可能性: 2个参数或3个参数.
由于原型的机制, 使得C语言没有办法阻止你写多于3个的参数, 只不过,
open的实现不会理会你传递给它的那些多余的参数, 而函数调用的参数传递机
制又会正确地消除你额外传递的垃圾参数而引起的堆栈开销. 所以, 并无害
处. 但下面的写法是正确的:
open("abc.txt", O_RDONLY, S_IRWXU);
因为第二个参数中没有 O_CREAT, 所以open的实现不会去检查第三个参数.
而
open("abc.txt", O_WRONLY | O_CREAT, S_IRWXU, 1, 2, "asdf");
这样的写法也是合法的. gcc 加了参数-Wall也没有给出任何警告.
这正如 printf("%d", 1 ,2 ,3 , "adf" );
完全合法一样, 只不过 gcc特别为printf作了考虑, 它会用内窥镜看到printf
的内部, 深入其五脏六腑做检查, 第一个格式化字串内的每个格式转换说明符
与后面的参数是否类型匹配. 你调用printf时搞错了这个gcc是会有提醒的,
前提是你用了-Wall 参数.
阅读(1575) | 评论(0) | 转发(0) |