背景最近项目中需要用到posix消息队列查看其API发现mq_open函数比较特殊竟然有2个同名的函数签名mqd_tmq_open(constchar*name,intoflag);mqd_tmq_open(constchar*name,intoflag,mode_tmode,structmq_attr*attr);我记得C语言是不支持函数重载的这是怎么做到的呢分析这应该是在链接阶段耍的花招弱别名一开始以为是弱别名机制但是看完这篇文章后感觉并不能解答问题严格别名又翻到这篇文章感觉更不相关。翻glibc源码在glibc的源码文件rt/bits/mqueue2.h和sysdeps/unix/sysv/linux/mq_open.c里找到了答案原来是通过变参函数来实现的运行时“重载”声明rt/bits/mqueue2.h检查第二个参数oflags如果O_CREAT置位则调用4参数版本否则调用2参数版本externmqd_tmq_open(constchar*__name,int__oflag,...)__THROW__nonnull((1));externmqd_t__mq_open_2(constchar*__name,int__oflag)__THROW__nonnull((1));externmqd_t__REDIRECT_NTH(__mq_open_alias,(constchar*__name,int__oflag,...),mq_open)__nonnull((1));__errordecl(__mq_open_wrong_number_of_args,mq_open can be called either with 2 or 4 arguments);__errordecl(__mq_open_missing_mode_and_attr,mq_open with O_CREAT in second argument needs 4 arguments);__fortify_functionmqd_t__NTH(mq_open(constchar*__name,int__oflag,...)){if(__va_arg_pack_len()!0__va_arg_pack_len()!2)__mq_open_wrong_number_of_args();if(__builtin_constant_p(__oflag)){if((__oflagO_CREAT)!0__va_arg_pack_len()0){__mq_open_missing_mode_and_attr();return__mq_open_2(__name,__oflag);}return__mq_open_alias(__name,__oflag,__va_arg_pack());}if(__va_arg_pack_len()0)return__mq_open_2(__name,__oflag);return__mq_open_alias(__name,__oflag,__va_arg_pack());}实现sysdeps/unix/sysv/linux/mq_open.c__mq_open是4参数版本__mq_open_2是2参数版本其实就是将第三第四个参数置空然后传给4参数版本。mqd_t__mq_open(constchar*name,intoflag,...){if(name[0]!/)returnINLINE_SYSCALL_ERROR_RETURN_VALUE(EINVAL);mode_tmode0;structmq_attr*attrNULL;if(oflagO_CREAT){va_list ap;va_start(ap,oflag);modeva_arg(ap,mode_t);attrva_arg(ap,structmq_attr*);va_end(ap);}returnINLINE_SYSCALL(mq_open,4,name1,oflag,mode,attr);}strong_alias(__mq_open,mq_open);mqd_t__mq_open_2(constchar*name,intoflag){if(oflagO_CREAT)__fortify_fail(invalid mq_open call: O_CREAT without mode and attr);return__mq_open(name,oflag);}验证给mq_open传递3个参数编译链接通过说明glibc确实用的变参函数否则编译一定通不过。#includestdio.h#includestdlib.h#includefcntl.h#includesys/stat.h#includemqueue.hmqd_tq;intmain(){qmq_open(/mq,O_CREAT,S_IRWXU);return0;}神奇的是运行时也未抛出异常。后记其实open、openat系统调用也是通过变参函数实现的函数重载效果