在阅读_splitpath_s()
的文档时,一个小细节引起了我的注意。它在其1st参数中获取磁盘项的路径(例如,C:\Temp\MyFile.exe),然后将其拆分为驱动器、目录和扩展名。然而,奇怪的是,它要求字符串缓冲区的长度,该缓冲区将在其3rd参数中保存驱动器的名称作为回报。
据我所知,驱动器号只能是两个字母的字符串;后跟分号的字母,如A:
、B:
、C:
等。因此,在所有情况下,它都必须是两个字符的字符串。但如果是这样,_splitpath_s()
为什么要求驱动器号的长度?有没有哪种驱动器号可以采用不同的格式?如果它不询问它的长度,只假设它是2,那么在最坏的情况下会发生什么问题?
errno_t _splitpath_s(
const char * path,
char * drive,
size_t driveNumberOfElements,
char * dir,
size_t dirNumberOfElements,
char * fname,
size_t nameNumberOfElements,
char * ext,
size_t extNumberOfElements
);
_s
函数的重点是对缓冲区溢出保持偏执。因此,所有缓冲区都应该与一个大小相关联。
您建议使用两个字符的字符串,这意味着冒号将被省略(从使用角度来看,这将是令人讨厌的),或者意味着字符串没有以NUL结尾,这可能是出乎意料的(尤其是因为它与所有其他输出参数不一致,被NUL终止),然后可能导致其他安全漏洞。
即使您修改了您的建议,使用三个字符而不是两个字符的固定大小缓冲区,在C中,向函数声明数组参数实际上也没有任何作用;编译器不会强制要求参数是大小正确的数组。也就是说,一个类似于的函数
void foo(int array[3]);
实际上与没有什么不同
void foo(int* array);
如果_splitpath_s
不采用driveNumberOfElements
参数,那么调用方将更容易意外地传递过小的缓冲区。虽然调用方在当前形式下仍然可以这样做,但显式driveNumberOfElements
参数的存在应该会让调用方注意到这一点。
最后,从理论上讲,有朝一日驱动器可能不会局限于单个字符,因此采用driveNumberOfElements
参数的_splitpath_s
版本更适合未来使用。(然而,在实践中,这样的更改会破坏许多现有代码。)