У меня есть часть кода, который выводы различные результаты, в зависимости от компилятора 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?
(BTW, согласно http://msdn.microsoft.com/en-us/library/system.string.aspx, которым вывод должен быть 0, таким образом, ответ mono является неправильным, но это не связано с моим вопросом.)
Даже сгенерированный код 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
Компиляция с моно:
.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
Единственной разницей являются две дополнительных инструкции по NOP в версии .NET.
Как это возможно? Как эти два выходных значения могут отличаться?
Кроме того, если у кого-либо есть и .NET и моно установленный, можно ли воспроизвести его?
Править: Я не забочусь о том, что корректный результат, и я не забочусь, что моно и .NET приводит к различным результатам. Я никогда не буду, вероятно, встречаться встроенный, аннулирует, И отсортируйте их, И порядок сортировки будет важен.
Моя проблема состоит в том, что то же время выполнения (.Net 2.0) приводит к различным результатам при компиляции различными компиляторами.
РЕДАКТИРОВАНИЕ 2: Я добавил таблицу и попытался разъяснить вопрос, должно быть легче понять теперь.
Это связано с упорядочиванием строк? См. эту запись в блоге Марка
Моя догадка заключается в том, что когда вы компилируете его с помощью Mono, он ссылается на версию mscorlib .NET 2.0 - тогда как когда вы скомпилируйте его с помощью VS, он нацелен на .NET 4.0.
Я могу ошибаться в отношении того, какая именно версия является целевой в каждом случае, но я бы начал с этого: не смотрите на IL для метода, посмотрите на сборки, на которые есть ссылки.
(Может помочь, если вы скажете, какие версии VS, .NET и Mono у вас установлены, кстати.)
РЕДАКТИРОВАТЬ: Хорошо, если он делает то же самое, независимо от того, на какую версию вы нацеливаетесь , как насчет выполнения сравнения результатов запуска ildasm для каждой версии? Сравните файлы целиком, а не только IL для самого вызова метода.
Я думаю, что это просто еще одна несовместимость Mono с .NET (особенно в System.String::Compare при обработке информации о культуре), поэтому, пожалуйста, напишите отчет, чтобы сообщить команде Novell/Mono. Они смогут получить обратную связь и подтвердить, является ли это желаемым. Если это ошибка, вы будете знать, по крайней мере, когда она может быть исправлена.
Я предполагаю, что asm-команды nop (No Operation) предназначены для выравнивания команд в памяти. Это дает возможность процессору загружать код во внутренний кеш и, следовательно, запускать его быстрее. Это довольно стандартный метод оптимизации, и кажется, что компилятор .NET делает это, в то время как Mono это не волнует.
Сравнение строк определяется параметром CultureInfo.CompareInfo
. Я предполагаю, что CultureInfo.CompareInfo
возвращает разные битовые маски в .Net и Mono. .Net 3.5 возвращает 0xff
, когда я печатаю System.Globalization.CultureInfo.InvariantCulture.CompareInfo
. Что печатается в монохромном режиме? Сравните недостающие биты с System.Globalization.CultureInfo.CompareOptions
. Если битовые маски одинаковы, значит, в Mono или .Net есть ошибка в интерпретации информации о культуре.
Имея это в виду, я бы очень не хотел, чтобы в вашем коде была какая-либо заметная разница, если дизассемблирование будет таким же.