我有一段代码,它根据C#编译器和运行时输出不同的结果。
有问题的代码是:
using System;
public class Program {
public static void Main() {
Console.WriteLine(string.Compare("alo\0alo\0", "alo\0alo\0\0", false, System.Globalization.CultureInfo.InvariantCulture));
}
}
结果是:
Compiling with mono (gmcs) Compiling with .Net (csc)
Running with mono -1 -1
Running with .Net -1 0
使用.Net框架运行时,如何输出不同的值?
(顺便说一下,根据http://msdn.microsoft.com/en-us/library/system.string.aspx,输出应为0,因此单声道的答案不正确,但这与我的问题无关。)
即使生成的IL代码也(几乎)相同。
使用.Net进行编译:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 29 (0x1d)
.maxstack 8
IL_0000: nop
IL_0001: ldstr bytearray (61 00 6C 00 6F 00 00 00 61 00 6C 00 6F 00 00 00 ) // a.l.o...a.l.o...
IL_0006: ldstr bytearray (61 00 6C 00 6F 00 00 00 61 00 6C 00 6F 00 00 00 // a.l.o...a.l.o...
00 00 )
IL_000b: ldc.i4.0
IL_000c: call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
IL_0011: call int32 [mscorlib]System.String::Compare(string,
string,
bool,
class [mscorlib]System.Globalization.CultureInfo)
IL_0016: call void [mscorlib]System.Console::WriteLine(int32)
IL_001b: nop
IL_001c: ret
} // end of method Program::Main
使用mono进行编译:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 27 (0x1b)
.maxstack 8
IL_0000: ldstr bytearray (61 00 6C 00 6F 00 00 00 61 00 6C 00 6F 00 00 00 ) // a.l.o...a.l.o...
IL_0005: ldstr bytearray (61 00 6C 00 6F 00 00 00 61 00 6C 00 6F 00 00 00 // a.l.o...a.l.o...
00 00 )
IL_000a: ldc.i4.0
IL_000b: call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
IL_0010: call int32 [mscorlib]System.String::Compare(string,
string,
bool,
class [mscorlib]System.Globalization.CultureInfo)
IL_0015: call void [mscorlib]System.Console::WriteLine(int32)
IL_001a: ret
} // end of method Program::Main
唯一的区别是.Net版本中的两个额外NOP指令。
怎么可能?两个输出值如何不同?
另外,如果有人同时安装了.Net和单声道,你可以重现它吗?
编辑:我不在乎正确的结果是什么,我不在乎单声道和.Net会产生不同的结果。我可能永远不会遇到嵌入的空值并对它们进行排序,排序顺序很重要。
我的问题是,当不同的编译器编译时,相同的运行时(。Net 2.0)会产生不同的结果。
编辑2:我添加了一张表并尝试澄清问题,现在应该更容易理解。
答案 0 :(得分:3)
我的猜测是当你用Mono编译它时,它引用了mscorlib的.NET 2.0版本 - 而当你用VS编译它时,它的目标是.NET 4.0。
我可能不确定在每种情况下针对哪个确切版本,但这是我要开始的地方:不要查看IL的方法,查看引用的程序集。
(如果你说你安装了哪个版本的VS,.NET和Mono,顺便说一句,可能会有所帮助。)
编辑:好的,所以如果无论你的目标是什么版本都会做同样的事情,那么在每个版本上运行ildasm的结果上运行差异怎么样?比较整个文件,而不仅仅是方法调用本身的IL。
答案 1 :(得分:2)
这与字符串排序有关吗?请参阅Marc的this博客条目
答案 2 :(得分:1)
我认为这只是另一个Mono与.NET的不兼容性(特别是在处理文化信息时在System.String :: Compare中),所以请记录一个报告以通知Novell / Mono团队。他们可以反馈并确认是否需要。如果这是一个错误,你至少知道什么时候可以修复。
答案 3 :(得分:0)
字符串比较由CultureInfo.CompareInfo
确定。我的猜测是CultureInfo.CompareInfo
在.Net与Mono上返回不同的位掩码。当我打印0xff
时,.Net 3.5返回System.Globalization.CultureInfo.InvariantCulture.CompareInfo
。在Mono下打印什么?将缺失位与System.Globalization.CultureInfo.CompareOptions
进行比较。如果位掩码相同,则Mono或.Net中的文化信息如何被解释。
考虑到这一点,如果反汇编是相同的话,我会非常注意你的代码中的任何可观察的差异。
答案 4 :(得分:0)
我猜想nop(No Operation)asm命令用于在内存中对齐命令。这使CPU有机会将代码加载到内部缓存中,从而更快地运行它。这是非常标准的优化技术,似乎.NET编译器在Mono不关心的情况下完成它。