我刚刚安装了 C++ Builder 12,想要编译一个古老的软件,它使用 TFileStream 来读取和写入 C 风格的缓冲区。例如:
DWORD MyFileStream::Read (BYTE *Buffer, DWORD Count)
{
try
{
if (File)
return File->Read(Buffer, Count) ;
}
catch(...)
{
LastError = GetLastError() ;
return MY_ERROR_READ ;
}
return 0x00 ;
}
这在 32 位中仍然可以正常编译,但是(从 c++ Builder 11.3 到 12)它现在不再在 64 位中编译。 所以,大约 20 年后,我不得不去查看帮助文件中的 TFileStream,它似乎只使用 DynamicArray ?
困惑? 那为什么它编译成32位呢? 我感觉帮助文件不完整? 更重要的是,如何在不创建动态数组的情况下解决这个问题(假设仍然可能)?
错误:
call to member function 'Read' is ambiguous
[C++ Error] System.Classes.hpp(1756, 36): candidate function
[C++ Error] System.Classes.hpp(1771, 38): candidate function
[C++ Error] System.Classes.hpp(1777, 36): candidate function not viable: no known conversion from 'BYTE *' (aka 'unsigned char *') to 'System::Sysutils::TBytes &' (aka 'DynamicArray<unsigned char> &') for 1st argument
[C++ Error] System.Classes.hpp(1779, 38): candidate function not viable: no known conversion from 'BYTE *' (aka 'unsigned char *') to 'System::Sysutils::TBytes &' (aka 'DynamicArray<unsigned char> &') for 1st argument
[C++ Error] System.Classes.hpp(1773, 36): candidate function not viable: requires 3 arguments, but 2 were provided
[C++ Error] System.Classes.hpp(1775, 38): candidate function not viable: requires 3 arguments, but 2 were provided
所以,大约 20 年后,我不得不去查看帮助文件中的 TFileStream,它似乎只使用 DynamicArray ?
这是不正确的。它仍然具有使用原始缓冲区的重载。
真正的罪魁祸首是
Read()
(和Write()
)仅在64位下有额外的重载,这些重载尚未记录,但如果你查看System.Classes.hpp
中的声明,你会看到它们:
public:
virtual System::LongInt __fastcall Read(void *Buffer, System::LongInt Count)/* overload */;
virtual System::LongInt __fastcall Write(const void *Buffer, System::LongInt Count)/* overload */;
#ifdef _WIN64
virtual System::NativeInt __fastcall Read(void *Buffer, System::NativeInt Count)/* overload */;
virtual System::NativeInt __fastcall Write(const void *Buffer, System::NativeInt Count)/* overload */;
#endif /* _WIN64 */
virtual System::LongInt __fastcall Read(System::Sysutils::TBytes Buffer, System::LongInt Offset, System::LongInt Count)/* overload */;
virtual System::LongInt __fastcall Write(const System::Sysutils::TBytes Buffer, System::LongInt Offset, System::LongInt Count)/* overload */;
#ifdef _WIN64
virtual System::NativeInt __fastcall Read(System::Sysutils::TBytes Buffer, System::NativeInt Offset, System::NativeInt Count)/* overload */;
virtual System::NativeInt __fastcall Write(const System::Sysutils::TBytes Buffer, System::NativeInt Offset, System::NativeInt Count)/* overload */;
#endif /* _WIN64 */
System::LongInt __fastcall Read(System::Sysutils::TBytes &Buffer, System::LongInt Count)/* overload */;
System::LongInt __fastcall Write(const System::Sysutils::TBytes Buffer, System::LongInt Count)/* overload */;
#ifdef _WIN64
System::NativeInt __fastcall Read(System::Sysutils::TBytes &Buffer, System::NativeInt Count)/* overload */;
System::NativeInt __fastcall Write(const System::Sysutils::TBytes Buffer, System::NativeInt Count)/* overload */;
#endif /* _WIN64 */
这意味着仅在 64 位下,您尝试调用的 2 参数
Read()
现在接受 LongInt
和 NativeInt
类型作为缓冲区大小,并且因为 DWORD
可以隐式转换为这两种类型,这就是为什么您的代码现在在 64 位下不明确,但在 32 位下不明确。
要解决此问题,您需要通过将
DWORD
类型转换为所需类型来显式告诉编译器要调用哪个重载。