Тот же код IL, другой вывод - как это возможно? - PullRequest
9 голосов
/ 11 мая 2010

У меня есть кусок кода, который выводит разные результаты, в зависимости от компилятора 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 framework?

(Кстати, согласно 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

Единственное отличие - две дополнительные инструкции NOP в версии .Net.

Как это возможно?Чем могут отличаться два выходных значения?

Кроме того, если у кого-нибудь установлены и .Net, и моно, вы можете воспроизвести его?

РЕДАКТИРОВАТЬ: Мне все равно каков правильный результат, и Мне все равно , что моно и .Net дают разные результаты.Я, вероятно, никогда не столкнусь со встроенными нулями и сортирую их, и порядок сортировки будет важен.

Моя проблема в том, что один и тот же runtime (.Net 2.0) дает разные результаты, когда скомпилировано различными компиляторами.

РЕДАКТИРОВАТЬ 2: Я добавил таблицу и попытался прояснить вопрос, теперь это должно быть легче понять.

Ответы [ 5 ]

3 голосов
/ 11 мая 2010

My думаю, заключается в том, что когда вы компилируете его с помощью Mono, он ссылается на версию mscorlib для .NET 2.0, тогда как при компиляции с использованием VS он нацелен на .NET 4.0.

Возможно, я не прав насчет того, какая именно версия нацелена в каждом случае, но вот с чего я бы хотел начать: не смотрите на IL для метода, посмотрите на ссылочные сборки.

(Это может помочь, если вы скажете, какие версии VS, .NET и Mono у вас установлены, кстати.)

РЕДАКТИРОВАТЬ: Хорошо, поэтому, если он делает то же самое, независимо от того, какую версию вы нацеливаете, как насчет запуска diff для результатов запуска ildasm для каждой версии? Сравните целые файлы, а не только IL для самого вызова метода.

2 голосов
/ 11 мая 2010

Это связано с порядком строк? Смотрите эту запись в блоге Марка

1 голос
/ 11 мая 2010

Я думаю, что это просто еще одна несовместимость Mono с .NET (особенно в System.String :: Compare при обработке информации о культуре), поэтому, пожалуйста, зарегистрируйте отчет, чтобы сообщить об этом команде Novell / Mono. Они могут оставить отзыв и подтвердить, желательно ли это. Если это ошибка, вы будете знать, по крайней мере, когда ее можно исправить.

http://www.mono -project.com / Bugs

0 голосов
/ 11 мая 2010

Я бы предположил, что команды asm nop (No Operation) предназначены для выравнивания команд в памяти. Это дает процессору шанс загрузить код во внутренний кеш и, следовательно, запустить его быстрее. Это довольно стандартная техника оптимизации, и кажется, что компилятор .NET делает это, а Mono это не волнует

0 голосов
/ 11 мая 2010

Сравнение строк определяется CultureInfo.CompareInfo. Я думаю, что CultureInfo.CompareInfo возвращает разные битовые маски в .Net против Mono. .Net 3.5 возвращает 0xff, когда я печатаю System.Globalization.CultureInfo.InvariantCulture.CompareInfo. Что он печатает под Mono? Сравните недостающие биты с System.Globalization.CultureInfo.CompareOptions. Если битовые маски совпадают, то в Mono или .Net есть ошибка в интерпретации информации о культуре.

Имея это в виду, я бы высоко оценил разницу между вашим кодом, если разборка такая же.

...