简体   繁体   English

C#到C ++ / CLI转换的陷阱

[英]Pitfalls of C# to C++/CLI conversion

I've been asked to translate some C# code into C++/CLI. 我被要求将一些C#代码转换为C ++ / CLI。 One of my managers has asked about potential pitfalls with the concept of translation between the two. 我的一位经理询问了两者之间翻译概念的潜在陷阱。

I'm well aware that both languages are compiled down to the Common Interface Language, and run through the same Common Language Runtime. 我很清楚这两种语言都被编译成通用接口语言,并在相同的通用语言运行时中运行。 However, can one guarantee that a piece of C# code which is compiled for the .NET Framework 4.5 and calls File.Exists(someFile); 但是,可以保证为.NET Framework 4.5编译并调用File.Exists(someFile);的一段C#代码。 will compile down to the CIL in exactly the same way as a piece of C++/CLI code which is compiled for the .NET Framework 4.5 and calls File::Exists(someFile); 将以为.NET Framework 4.5编译并调用File :: Exists(someFile)的C ++ / CLI代码完全相同的方式编译为CIL。 ?

In theory the answer is yes, since this seems to be what the .NET framework is built for. 从理论上讲,答案是肯定的,因为这似乎是.NET框架的基础。 However, is there a way of validating this? 但是,有没有一种方法可以验证这一点? Is there a technical reason why it must be/cannot be the case? 是否出于某种技术原因必须/不可能如此?

There certainly are some pitfalls when you write C++/CLI code and you know C# well but not C++/CLI. 编写C ++ / CLI代码时肯定会有一些陷阱,并且您对C#非常了解,但对C ++ / CLI却不了解。 I'll avoid turning this into a list question and enumerate all of them, just the more common mistakes: 我将避免把它变成一个列表问题,并列举所有这些,只是更常见的错误:

  • C++/CLI requires you to be specific in the language syntax about the difference between value types and reference types. C ++ / CLI要求您具体说明值类型和引用类型之间的区别的语言语法。 You have to use the hat^ on reference type references. 您必须在引用类型引用上使用hat ^。 Like String^ foo; String^ foo; . But sometimes you don't, you intentionally omit it. 但是有时您没有,则有意忽略了它。 Like StreamReader file; StreamReader file;一样StreamReader file; . Which enables "stack semantics", an emulation of the C++ RAII pattern. 启用“堆栈语义”,这是C ++ RAII模式的仿真。 Or in other words, the compiler will automatically dispose the file variable when it goes out of scope. 换句话说,当超出范围时,编译器将自动处理文件变量。 You know this from the C# using statement. 您可以从C# using语句知道这一点。 The biggest trap is using the hat when you should not, like int^ x = 42; 最大的陷阱是当您不应该使用帽子时,例如int^ x = 42; . Which the compiler will accept without a complaint, but you end up with a boxed int which is extremely inefficient at runtime. 编译器会毫无保留地接受它,但是最终会得到一个装箱的int,这在运行时效率极低。

  • Development on the C++/CLI language and toolset stopped in 2005 and has been in maintenance mode since. C ++ / CLI语言和工具集的开发于2005年停止,此后一直处于维护模式。 It thus didn't acquire the goodies that C# got in that time frame, Linq certainly being the most significant addition. 因此,它没有获得C#在那个时间范围内获得的好处,Linq当然是最重要的补充。 No lambda expression support, no anonymous types, no extension methods. 没有lambda表达式支持,没有匿名类型,没有扩展方法。 You will not enjoy converting C# code that uses these syntax constructs. 您将不会喜欢转换使用这些语法结构的C#代码。

  • There is only ever one reason to consider converting C# to C++/CLI, it is to take advantage of its great support for interop with unmanaged code. 只有不断的原因之一考虑C#转换为C ++ / CLI,它是采取的与非托管代码互操作的大力支持优势。 No need to wrangle pinvoke. 无需纠结pinvoke。 A very common mistake is to compile everything to MSIL, including the native C++ code. 一个非常常见的错误是将所有内容编译为MSIL,包括本机C ++代码。 Which works too well, the C++/CLI compiler is capable of compiling any C++ to IL as long as it is standard C++03 compliant code. 效果很好,C ++ / CLI编译器能够将任何C ++编译为IL,只要它是符合C ++ 03的标准代码即可。 But the result is inefficient , it certainly doesn't run as managed code at runtime and is jitted like normal but without the goodies from the native code generator. 但是结果是效率低下的 ,它肯定不会在运行时作为托管代码运行,并且像正常情况一样抖动,但是没有本机代码生成器的好处。 Which can do a better job optimizing code. 哪个可以更好地优化代码。

  • The output of the compiler is plain MSIL, the exact same kind that C# generates. 编译器的输出是普通的MSIL,与C#生成的完全相同。 Plus native code for the parts of your program where you use C++, producing a mixed-mode assembly. 加上使用C ++的程序各部分的本地代码,从而生成混合模式的程序集。 This gives the assembly a dependency on the bitness of the process. 这使程序集依赖于过程的细节。 Or in other words, the AnyCPU target you might know from C# projects does not apply. 换句话说,您可能从C#项目中知道的AnyCPU目标不适用。 This is something you need to be aware of in your EXE project, you must be explicit about the Platform target setting. 这是您在EXE项目中需要注意的事项,必须明确了解Platform目标设置。 With "x86" the common choice to ensure that your program will still work when it runs on a 64-bit operating system. 使用“ x86”是确保您的程序在64位操作系统上运行时仍能正常工作的常用选择。 If you want to run your program as a 64-bit process on a 64-bit OS then you'll need to create two builds of your C++/CLI assembly and deploy the correct one with your installer. 如果要在64位OS上将程序作为64位进程运行,则需要创建两个 C ++ / CLI程序集版本,并使用安装程序部署正确的程序集。

You have nothing to fear from a File::Exists(somefile) call, there's only one way to call that method in MSIL. 您不必担心File :: Exists(somefile)调用,在MSIL中只有一种方法可以调用该方法。 The C++/CLI compiler will generate the exact same IL as the C# compiler. C ++ / CLI编译器将生成与C#编译器完全相同的IL。 If you are really concerned about it then create confidence by looking at the IL with a decompiler like ildasm.exe 如果您真的很担心,那么可以使用ildasm.exe这样的反编译器查看IL,从而建立信心。

[C]an one guarantee that a piece of C# code which is compiled for the .NET Framework 4.5 and calls File.Exists(someFile); [C]确保已为.NET Framework 4.5编译并调用File.Exists(someFile);的一段C#代码File.Exists(someFile); will compile down to the CIL in exactly the same way as a piece of C++/CLI code which is compiled for the .NET Framework 4.5 and calls File::Exists(someFile); 将以为.NET Framework 4.5编译并调用File::Exists(someFile);的C ++ / CLI代码完全相同的方式编译为CIL File::Exists(someFile); ?

No, this is not guaranteed. 不,不能保证。

In fact, it's not even guaranteed that two runs of the same source code through the C# compiler will produce the same binary output . 实际上, 甚至不能保证通过C#编译器运行两次相同的源代码会产生相同的二进制输出 So certainly two different compilers for two different languages can be expected to possibly generate different code. 因此,可以肯定,两种不同语言的两种不同编译器可能会生成不同的代码。

(Mind you, it might , and in reality it probably often does . But we're talking about guarantees here.) (请记住, 可能 ,实际上可能经常这样做 。但是我们在这里谈论担保 。)

What I cannot understand is why this would possibly matter. 我不明白的是为什么这可能很重要。 The code will do the same thing, of course, since it's calling the same method. 由于调用了相同的方法,因此代码将执行相同的操作。 Not only is that guaranteed by the documentation, it's self-verifiable by disassembling the .NET Framework DLLs. 不仅由文档保证,而且还可以通过反汇编.NET Framework DLL进行自我验证。

The two programs just aren't guaranteed to have identical binaries. 不能保证两个程序都具有相同的二进制文件。 Not that anything will anyway once it passes through the JIT compiler. 一旦通过JIT编译器,就不会有任何反应。 That's kind of the whole point. 这就是重点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM