K&R《C程序设计语言》qsort函数指针版强制转换合法性探究
关于K&R《C程序设计语言》qsort_alt的指针转换与标准合规性疑问解答
1. 为何调用qsort_alt时需显式转换参数?
K&R实现的qsort_alt函数第一个参数类型为void**,但实际测试传入的通常是char**、wchar_t**这类具体的指针数组(数组名会退化为指向首元素的指针)。由于void**与char**属于不同的指针类型,C标准(C99及后续版本)规定,不同对象指针类型之间的隐式转换仅允许在void*与其他对象指针之间进行,void**并不具备void*的通用指针特性。因此必须通过显式强制转换告知编译器我们确认类型转换的意图,否则编译器会抛出类型不匹配警告甚至拒绝编译。
2. (void**)linearr及(void**)wlinearr这类数组指针转换是否合法?
这类转换在C标准中允许但需谨慎:
- 首先,数组名在表达式中会自动转换为指向数组首元素的指针(如
char* linearr[]会退化为char**)。根据C11标准6.3.2.3第7条,任何指向对象类型的指针都可以转换为另一种对象指针类型,只要转换回原类型,其值能保持不变。 - 其次,
void*的大小与所有对象指针的大小相等(C11标准6.2.5第28条),因此char**转换为void**后,指针的存储大小和对齐要求不会出现冲突。 - 但需注意:转换后的指针若直接用于访问原类型以外的对象,可能触发实现定义的行为。不过
qsort_alt仅以void*为单位操作数组元素,原数组元素大小(如sizeof(char*))与sizeof(void*)完全一致,实际使用不会出问题,但严格来说这类转换不属于标准规定的“安全兼容”转换,依赖编译器实现行为。
3. numcmp/strcmp/wcscmp等函数指针转换为int (*)(void*, void*)是否合规?
这类转换标准允许,但转换后的函数调用属于未定义行为:
- C11标准6.3.2.3第8条规定,不同类型的函数指针之间可以强制转换,但只有转换回原函数指针类型后调用,行为才是定义良好的。
- 以
strcmp为例,其原型为int (*)(const char*, const char*),与int (*)(void*, void*)参数类型不兼容。即使调用时传入的void*实际指向char*,通过转换后的函数指针调用strcmp,本质是用不匹配的函数类型调用,违反C11标准6.5.2.2第9条(函数调用的参数类型必须与函数定义的参数类型兼容),属于未定义行为——主流编译器通常会按预期处理,但无法保证所有架构或编译器下都能正常工作。
4. qsort_alt中对comp的调用是否存在问题?
结合上述函数指针的问题,qsort_alt对comp的调用确实存在标准合规性问题:
- 如果
comp是由strcmp这类原参数带const修饰的函数转换而来,qsort_alt的comp参数类型int (*)(void*, void*)没有const限定符,会导致参数类型兼容性进一步恶化——const char*与void*的兼容度更低,调用时会丢弃const属性,虽编译器可能不报错,但违反了const的语义约定。 - 更关键的是,如问题3所述,通过不兼容的函数指针类型调用函数本身就是未定义行为,无论实际参数值是否正确,标准无法保证调用结果的正确性或程序稳定性。
内容的提问来源于stack exchange,提问作者Lover of Structure
相关产品推荐
相关产品推荐

