Jestem nowy w .Net i najpierw próbuję zrozumieć podstawy. Jaka jest różnica między kodem bajtowym MSIL i kodem bajtowym Java?
Jestem nowy w .Net i najpierw próbuję zrozumieć podstawy. Jaka jest różnica między kodem bajtowym MSIL i kodem bajtowym Java?
Odpowiedzi:
Po pierwsze, pozwólcie mi powiedzieć, że nie sądzę, aby subtelne różnice między kodem bajtowym Javy a MSIL były czymś, co powinno przeszkadzać początkującym programistom .NET. Oba służą temu samemu celowi, definiując abstrakcyjną maszynę docelową, która jest warstwą nad maszyną fizyczną używaną na końcu.
Kod bajtowy MSIL i Java są bardzo podobne, w rzeczywistości istnieje narzędzie o nazwie Grasshopper, które tłumaczy MSIL na kod bajtowy Java. Byłem częścią zespołu programistów Grasshopper, więc mogę podzielić się odrobiną mojej (wyblakłej) wiedzy. Zwróć uwagę, że przestałem nad tym pracować, gdy pojawił się .NET framework 2.0, więc niektóre z tych rzeczy mogą już nie być prawdziwe (jeśli tak, zostaw komentarz, a ja go poprawię).
struct
).enums
to niewiele więcej niż otoki wokół typów całkowitych, podczas gdy Javaenums
to prawie pełnoprawne klasy (dzięki Internet Friendowi za komentarz).out
i ref
parametry.Istnieją inne różnice językowe, ale większość z nich nie jest wyrażona na poziomie kodu bajtowego, na przykład, jeśli pamięć obsługuje nie static
wewnętrzne klasy Javy (które nie istnieją w .NET) nie są funkcją kodu bajtowego, kompilator generuje dodatkowy argument do konstruktor klasy wewnętrznej i przekazuje obiekt zewnętrzny. To samo dotyczy wyrażeń lambda .NET.
CIL (właściwa nazwa dla MSIL) i kod bajtowy Java są bardziej takie same niż różne. Jest jednak kilka ważnych różnic:
1) CIL został zaprojektowany od początku, aby służyć jako cel dla wielu języków. W związku z tym obsługuje znacznie bogatszy system typów, w tym typy podpisane i niepodpisane, typy wartości, wskaźniki, właściwości, delegatów, zdarzenia, typy ogólne, system obiektowy z jednym korzeniem i więcej. CIL obsługuje funkcje, które nie są wymagane dla początkowych języków CLR (C # i VB.NET), takie jak funkcje globalne i optymalizacje wywołań końcowych . Dla porównania, kod bajtowy Java został zaprojektowany jako cel dla języka Java i odzwierciedla wiele ograniczeń występujących w samej Javie. Byłoby znacznie trudniej napisać C lub Scheme przy użyciu kodu bajtowego Java.
2) CIL został zaprojektowany w celu łatwej integracji z natywnymi bibliotekami i niezarządzanym kodem
3) Kod bajtowy Java został zaprojektowany do interpretacji lub kompilacji, podczas gdy CIL został zaprojektowany z założeniem tylko kompilacji JIT. To powiedziawszy, początkowa implementacja Mono wykorzystywała interpreter zamiast JIT.
4) CIL został zaprojektowany ( i określony ) tak, aby miał czytelną dla człowieka i zapisywalną formę języka asemblera, która jest odwzorowywana bezpośrednio na postać kodu bajtowego. Uważam, że kod bajtowy Java (jak sama nazwa wskazuje) miał być przeznaczony tylko do odczytu maszynowego. Oczywiście kod bajtowy Javy jest stosunkowo łatwo dekompilowany z powrotem do oryginalnej Javy i, jak pokazano poniżej, można go również „zdemontować”.
Powinienem zauważyć, że JVM (większość z nich) jest bardziej zoptymalizowany niż CLR (którykolwiek z nich). Tak więc nieprzetworzona wydajność może być powodem, aby preferować celowanie w kod bajtowy Java. Jest to jednak szczegół implementacji.
Niektórzy mówią, że kod bajtowy Javy został zaprojektowany jako wieloplatformowy, podczas gdy CIL został zaprojektowany tylko dla systemu Windows. Nie o to chodzi. W środowisku .NET jest kilka izmów „Windows”, ale nie ma ich w CIL.
Jako przykład punktu 4) powyżej, jakiś czas temu napisałem zabawkową Javę do kompilatora CIL. Jeśli zasilasz ten kompilator następującym programem Java:
class Factorial{
public static void main(String[] a){
System.out.println(new Fac().ComputeFac(10));
}
}
class Fac {
public int ComputeFac(int num){
int num_aux ;
if (num < 1)
num_aux = 1 ;
else
num_aux = num * (this.ComputeFac(num-1)) ;
return num_aux ;
}
}
mój kompilator wypluje następujący CIL:
.assembly extern mscorlib { }
.assembly 'Factorial' { .ver 0:0:0:0 }
.class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object
{
.method public static default void main (string[] a) cil managed
{
.entrypoint
.maxstack 16
newobj instance void class Fac::'.ctor'()
ldc.i4 3
callvirt instance int32 class Fac::ComputeFac (int32)
call void class [mscorlib]System.Console::WriteLine(int32)
ret
}
}
.class private Fac extends [mscorlib]System.Object
{
.method public instance default void '.ctor' () cil managed
{
ldarg.0
call instance void object::'.ctor'()
ret
}
.method public int32 ComputeFac(int32 num) cil managed
{
.locals init ( int32 num_aux )
ldarg num
ldc.i4 1
clt
brfalse L1
ldc.i4 1
stloc num_aux
br L2
L1:
ldarg num
ldarg.0
ldarg num
ldc.i4 1
sub
callvirt instance int32 class Fac::ComputeFac (int32)
mul
stloc num_aux
L2:
ldloc num_aux
ret
}
}
Jest to poprawny program CIL, który można wprowadzić do asemblera CIL, tak jak w ilasm.exe
celu utworzenia pliku wykonywalnego. Jak widać, CIL jest językiem w pełni czytelnym i zapisywalnym przez człowieka. Możesz łatwo tworzyć prawidłowe programy CIL w dowolnym edytorze tekstu.
Możesz również skompilować powyższy program Java za pomocą javac
kompilatora, a następnie uruchomić wynikowe pliki klas za pomocą javap
„dezasemblera”, aby uzyskać następujące informacje:
class Factorial extends java.lang.Object{
Factorial();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3; //class Fac
6: dup
7: invokespecial #4; //Method Fac."<init>":()V
10: bipush 10
12: invokevirtual #5; //Method Fac.ComputeFac:(I)I
15: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
18: return
}
class Fac extends java.lang.Object{
Fac();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public int ComputeFac(int);
Code:
0: iload_1
1: iconst_1
2: if_icmpge 10
5: iconst_1
6: istore_2
7: goto 20
10: iload_1
11: aload_0
12: iload_1
13: iconst_1
14: isub
15: invokevirtual #2; //Method ComputeFac:(I)I
18: imul
19: istore_2
20: iload_2
21: ireturn
}
Wynik javap
nie jest kompilowalny (o ile mi wiadomo), ale jeśli porównasz go z powyższym wynikiem CIL, zobaczysz, że są one bardzo podobne.
Zasadniczo robią to samo, MSIL to wersja kodu bajtowego Java firmy Microsoft.
Główne różnice wewnętrzne to:
O wiele więcej informacji i szczegółowe porównanie można znaleźć w artykule K John Gough (dokument postscriptowy)
CIL aka MSIL ma być czytelny dla człowieka. Kod bajtowy Java nie jest.
Pomyśl o kodzie bajtowym Java jako o kodzie maszynowym sprzętu, który nie istnieje (ale który emuluje maszyny JVM).
CIL jest bardziej podobny do języka asemblera - jeden krok od kodu maszynowego, a jednocześnie jest czytelny dla człowieka.
Nie ma tak dużych różnic. Oba są formatami pośrednimi napisanego przez Ciebie kodu. Po uruchomieniu maszyny wirtualne będą wykonywać zarządzany język pośredni, co oznacza, że maszyna wirtualna kontroluje zmienne i wywołania. Jest nawet język, którego w tej chwili nie pamiętam, który może działać na .Net i Javie w ten sam sposób.
Zasadniczo jest to po prostu inny format tego samego
Edycja: Znalazłem język (oprócz Scali): To FAN ( http://www.fandev.org/ ), wygląda bardzo interesująco, ale nie ma jeszcze czasu na ocenę
Zgoda, różnice są na tyle niewielkie, że można je przyjąć jako początkujący. Jeśli chcesz nauczyć się .Net zaczynając od podstaw, polecam przyjrzenie się Common Language Infrastructure i Common Type System.
Serge Lidin jest autorem porządnej książki o szczegółach MSIL: Expert .NET 2.0 IL Assembler . Mogłem również szybko przyswoić MSIL, patrząc na proste metody przy użyciu .NET Reflector i Ildasm (samouczek) .
Koncepcje między kodami bajtowymi MSIL i kodem bajtowym Java są bardzo podobne.
Myślę, że MSIL nie powinien być porównywany z kodem bajtowym Javy, ale „instrukcją zawierającą kody bajtowe Javy”.
Nie ma nazwy zdemontowanego kodu bajtowego Java. „Kod bajtowy Java” powinien być nieoficjalnym aliasem, ponieważ nie mogę znaleźć jego nazwy w oficjalnym dokumencie. Mówi dezasembler klas Java
Wyświetla zdezasemblowany kod, tj. Instrukcje zawierające kody bajtowe języka Java, dla każdej metody w klasie. Są one udokumentowane w specyfikacji wirtualnej maszyny języka Java.
Zarówno „Instrukcje Java VM”, jak i „MSIL” są składane w kodzie bajtowym .NET i kodzie Java, które nie są czytelne dla człowieka.