VS2017编译VS2012的C++/CLI头文件出现语法错误求解决
VS2017编译C++/CLI头文件出现C2059、C2143、C2447错误的原因及解决办法
先贴出你提供的原代码:
namespace CLIWrapper { public ref class Wrapper { public: static bool call_calculator(double* liquids, double* solids, double temperature, int arraySize); static void build_calculator(char** components, char* parameterSet, int arraySize); }; }
错误成因
- 编译器规范严格度升级:VS2012用的MSVC 11.0编译器对C++/CLI语法兼容性放得很宽,允许
double*、char**这类原生指针直接出现在托管类的公共方法签名里。但从VS2015开始(包括你用的VS2017,对应MSVC 15.x),编译器严格遵循ECMA-335 CLI标准——公共托管接口只能用CLI兼容的类型,原生指针不在这个范畴里,所以之前的“擦边球”写法直接触发了语法报错。 - 连锁语法错误:C2059是语法解析错误、C2143是语法元素缺失错误、C2447是无法识别的函数开头,本质都是原生指针出现在公共托管方法签名里引发的连锁问题。
解决办法
根据你的调用场景,有两种可行的修复方案:
方案一:仅在程序集内部或非托管代码中调用该方法
如果这些静态方法不需要暴露给其他程序集的托管代码调用,只需把方法的访问修饰符从public改成internal(对应.NET的程序集内可见),编译器就会放松对接口的CLI规范检查:
namespace CLIWrapper { public ref class Wrapper { internal: // 替换原来的public修饰符 static bool call_calculator(double* liquids, double* solids, double temperature, int arraySize); static void build_calculator(char** components, char* parameterSet, int arraySize); }; }
方案二:需要暴露给外部托管程序集调用
这种情况必须把原生指针替换为CLI兼容的托管类型,再在方法内部转换为原生指针调用非托管代码:
// 头文件代码 #include <msclr/marshal.h> #include <msclr/marshal_cppstd.h> namespace CLIWrapper { public ref class Wrapper { public: static bool call_calculator(cli::array<double>^ liquids, cli::array<double>^ solids, double temperature, int arraySize); static void build_calculator(cli::array<System::String^>^ components, System::String^ parameterSet, int arraySize); }; }
然后在实现文件中完成托管类型到原生指针的转换(以调用非托管函数为例):
// 实现文件代码 using namespace System; using namespace msclr::interop; bool CLIWrapper::Wrapper::call_calculator(cli::array<double>^ liquids, cli::array<double>^ solids, double temperature, int arraySize) { // 固定托管数组,获取原生指针(防止GC移动内存) pin_ptr<double> pinnedLiquids = &liquids[0]; pin_ptr<double> pinnedSolids = &solids[0]; // 调用你的非托管calculator函数 return your_non_managed_calculator(pinnedLiquids, pinnedSolids, temperature, arraySize); } void CLIWrapper::Wrapper::build_calculator(cli::array<String^>^ components, String^ parameterSet, int arraySize) { // 转换单个字符串为原生char* std::string paramSetStr = marshal_as<std::string>(parameterSet); char* paramSetPtr = const_cast<char*>(paramSetStr.c_str()); // 转换字符串数组为char** std::vector<char*> compPtrList; for each (String^ comp in components) { std::string compStr = marshal_as<std::string>(comp); compPtrList.push_back(const_cast<char*>(compStr.c_str())); } char** compsPtr = compPtrList.data(); // 调用你的非托管build_calculator函数 your_non_managed_build_calculator(compsPtr, paramSetPtr, arraySize); }
内容的提问来源于stack exchange,提问作者Connor Mote
相关产品推荐
相关产品推荐

