C标准是否保障返回同类型的旧式与原型化函数指针可隐式互转?
旧式函数指针与原型化函数指针的隐式转换是否符合C标准?
咱们直接把问题拆透:你测试的这种隐式转换行为并不完全受C标准保障,其中把无原型函数指针赋值给带原型的函数指针的操作,本质上属于编译器扩展特性,而非标准要求。
先看你给出的测试代码:
// 编译无警告 typedef void RetTp; RetTp oldfn(){}; RetTp newfn(int X){}; RetTp (*oldfnp)() = newfn; RetTp (*newfnp)(int X) = oldfn;
先讲C标准的明确规定
根据C99、C11及后续版本的标准:
- 允许把带原型的函数指针赋值给无原型的函数指针:无原型的函数指针(也就是
RetTp (*)()这种形式)在调用时会对参数执行默认提升(比如char转int、float转double),只要原函数的参数类型经过默认提升后和调用时的实际参数匹配,后续调用就是定义良好的。所以oldfnp = newfn这一步是符合标准的。 - 禁止把无原型的函数指针隐式转换为带原型的函数指针:标准要求,只有当两个函数指针指向的函数类型兼容时,隐式转换才合法。无原型的函数类型(
RetTp ())和带参数原型的函数类型(RetTp (int))并不兼容,所以newfnp = oldfn这一步属于未定义行为——标准不保证它能正常工作,具体行为由编译器决定。
再看编译器的实际表现
GCC、Clang、TCC这些编译器为了兼容大量遗留的C旧代码,都做了扩展支持:即使是标准里定义的未定义行为,它们也会宽容地接受这种转换,并且默认不发出警告。但如果你开启严格的标准检查选项(比如gcc -std=c99 -pedantic),编译器就会针对newfnp = oldfn这一行抛出类型不兼容的警告,这才是贴合C标准要求的表现。
总结一下:你的代码能编译通过是编译器的兼容扩展在起作用,并非所有场景都受C标准保障,反向转换(旧式→原型化)的行为在标准里是未定义的。
内容的提问来源于stack exchange,提问作者Petr Skocik
相关产品推荐
相关产品推荐

