У меня есть этот IL код из Expert .NET 2.0 IL Assembler от Сержа Лидина:
Это находится в файле CilTest.il:
//----------- Program header
.assembly extern mscorlib { auto }
.assembly OddOrEven { }
.module OddOrEven.exe
//----------- Class declaration
.namespace Odd.or {
.class public auto ansi Even extends [mscorlib]System.Object {
//----------- Field declaration
.field public static int32 val
//----------- Method declaration
.method public static void check( ) cil managed {
.entrypoint
.locals init (int32 Retval)
AskForNumber:
ldstr "Enter a number"
call void [mscorlib]System.Console::WriteLine (string)
call string [mscorlib]System.Console::ReadLine ()
ldsflda valuetype CharArray8 Format
ldsflda int32 Odd.or.Even::val
call vararg int32 sscanf(string,int8*,...,int32*)
stloc Retval
ldloc Retval
brfalse Error
ldsfld int32 Odd.or.Even::val
ldc.i4 1
and
brfalse ItsEven
ldstr "odd!"
br PrintAndReturn
ItsEven:
ldstr "even!"
br PrintAndReturn
Error:
ldstr "How rude!"
PrintAndReturn:
call void [mscorlib]System.Console::WriteLine (string)
ldloc Retval
brtrue AskForNumber
ret
} // End of method
} // End of class
} // End of namespace
//----------- Global items
.field public static valuetype CharArray8 Format at FormatData
//----------- Data declaration
.data FormatData = bytearray(25 64 00 00 00 00 00 00) // % d . . . . . .
//----------- Value type as placeholder
.class public explicit CharArray8
extends [mscorlib]System.ValueType { .size 8 }
//----------- Calling unmanaged code
.method public static pinvokeimpl("msvcrt.dll" cdecl)
vararg int32 sscanf(string,int8*) cil managed { }
Следующий файл находится в той же папке и называется CilTest.ilproj:
<Project Sdk = "Microsoft.Net.Sdk.il/7.0.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
</Project>
Я компилирую код, используя:
dotnet build -r win-x64 --self-contained -c release
Когда я запускаю код, я получаю эту ошибку:
Кажется, что вызов sscanf
возвращает 0 успешно отформатированных строк:
call vararg int32 sscanf(string,int8*,...,int32*)
Почему sscanf()
не работает?
Есть ли способ отладить код, чтобы понять, почему sscanf()
не работает?
Первые два параметра sscanf — это строки, а не строка и целое число.
Это точный код Сержа Лидина, написавшего книгу, поэтому он должен работать. Может ли это быть связано с использованием .NET Core вместо Framework?
У меня ограниченный опыт, но я всегда использовал метод PInvoke при вызове sscanf таким образом. Мы использовали что-то вроде:
.method private pinvokeimpl("msvcrt.dll" cdec1)
int32 sscanf _pinvoke(string, int8*)
cil; managed { }
Вы также можете просто написать свою собственную версию sscanf(MSVC )( GLIBC), поскольку это относительно простая функция, и включить ее в свою программу.
Как вы думаете, это как-то связано с использованием .NET Core? Это пример из книги, поэтому я предполагаю, что код правильный.
Добавьте ключевое слово «preservesig» после cil «managed», вот так:
//----------- Calling unmanaged code
.method public static pinvokeimpl("msvcrt.dll" cdecl)
vararg int32 sscanf(string,int8*) cil managed preservesig { }
В реализациях .NET старше 2.0 это ключевое слово необходимо, чтобы указать, что возвращаемое значение метода P/Invoke должно быть сохранено.
Что происходит в менее экзотической среде, например. просто исполняемый файл, запрограммированный на C? Я спрашиваю, потому что ошибиться при сканировании так легко....