c# ---> asembler

EL
  • Rejestracja:prawie 7 lat
  • Ostatnio:ponad 6 lat
  • Postów:8
0

Z tego co wiem każdy program napisany w języku wysokopoziomowym by zadziałać najpierw jest kompilowany na asemblera następnie na kod maszynowy. Jest jakaś możliwość żeby zobaczyć swój program jako kod asemblerowy? (sorry jak coś pomieszałam i tak nie jest :P)

JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

Co do rozgraniczenia na języki wysokiego i niskiego poziomu - to niejednoznaczne. Dla jednych językiem niskiego poziomu będzie asm, a np. C już będzie językiem wysokiego poziomu ;) Dla innych niekoniecznie.

Co do pytania. C# jest kompilowany do IL - Intermediate Language. Możesz się posłużyć takim narzędziem jak ILSpy do tego. Natomiast z tego co wiem, C# nie kompiluje się do typowego assemblera. C# pracuje na maszynie wirtualnej.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
1

@eliasta: w menu: Debug -> Windows -> Disassembly.

@Juhas, procesory nie wykonują kodu IL.

edytowany 2x, ostatnio: somekind
Zobacz pozostałe 3 komentarze
somekind
A w jakim języku są te polecenia dla procesora?
JU
Ale to jest wirtualna maszyna, a nie exec. Dlatego napisałem, że exe .NET nie kompiluje się do typowego assemblera, tylko do IL. Polecenia IL są tłumaczone przez wirtualną maszynę i wykonywane przez procesor. Zgadza się?
somekind
No tak, ale wirtualna maszyna musi przetłumaczyć z IL na assembler, aby procesor mógł ten kod wykonać.
JU
zgadza się. Mi chodzi o same pliki wynikowe .NET
somekind
No tak, a potem ten plik jest konwertowany do Assemblera i możesz sobie ten kod bez problemu podejrzeć w debugerze. :)
0

Program C# jest kompilowany w "locie" na instrukcje procesora po uruchomieniu programu .
Kompilacja w C# polega na przetworzeniu kodu źródłowego na język pośredni IL.
Typy podstawowe takie jak int , operacje dodawania, dzielenia itd są zdefiniowane w samym języku IL.
Implementacje niektórych metod dodaje też samo środowisko CLR . Wszystko po to żeby program działał jak najszybciej .

Do przeglądania kodu IL, metadanych , manifestu możesz użyć darmowego programu ildasm.exe, który powinien się znajdować w takim katalogu np.
"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.1 Tools\ildasm.exe"
Edytować kod IL najwygodniej jest w Visual Studio Code . A do ponownej kompilacji kodu IL możesz użyć programu Ilasm.exe . https://docs.microsoft.com/pl-pl/dotnet/framework/tools/ilasm-exe-il-assembler

Jest jeszcze takie coś: Kompilowanie aplikacji z architekturą .NET Native ale ja jeszcze tego nie próbowałem.

Specyfikację języka IL możesz pobrać ze strony : https://www.ecma-international.org/publications/standards/Ecma-335.htm
Warto znać język IL. Możesz wtedy ręcznie zoptymalizować kod .

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
1
Zimny Krawiec napisał(a):

Warto znać język IL. Możesz wtedy ręcznie zoptymalizować kod .

Zrobiłeś to kiedyś? Albo ktokolwiek kiedykolwiek?

0

Wiele razy . Na początku szło opornie ale potem język IL wydaje się bardzo prosty .
Jedna rzecz która jest trochę męcząca dla mnie , Standardowe biblioteki NET wyglądają trochę inaczej niż to co daje kompilator C# .
Wyglądają tak jakby ktoś je ręcznie pisał bez używania kompilatora.
Kompilator C# często dodaje dużo nadmiarowego kodu , który można pominąć .

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
1

A jakie były mierzalne efekty tego działania? I jak organizujesz pracę, aby tych ręczne optymalizacje nie zniknęły po ponownej kompilacji projektu?

0

Jak chcesz pisać w IL to musisz się przyzwyczaić że to działa na zasadzie stosu ,
Możesz wrzucić kilka danych na stos a potem je zdejmować,
Czasem bardzo jest to nieczytelne i męczące .

0

Nie do końca zrozumiałem o co pytasz ,
Mierzalnym efektem jest np. zmniejszenie o 30% objętości kodu albo zorbienie czegoś na co nie pozwala kompilator C# a pozwala środowisko CLR .

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
0

A jakie praktyczne znaczenie ma objętość kodu? I o jakie rzeczy, które CLR może, a C# nie chodzi?
Dla mnie mierzalny efektem optymalizacji jest zoptymalizowanie czegoś. ;) Czyli szybkości działania albo zużycia pamięci w jakiś znaczący i zauważalny dla użytkowników sposób.

edytowany 1x, ostatnio: somekind
JP
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 miesiące
  • Postów:1065
0

@somekind: No jak Ty nie rozumiesz. Przecież to proste: "musisz się przyzwyczaić że to działa na zasadzie stosu". STOSU!!! :)
ROTFL

Aaa, przypomniałem sobie, że to ja właściwie napisałem trochę kodu w IL ale to był inny IL, z IEC 61131-3. I tam faktycznie były rzeczy, których w innym języku się nie dało napisać, przynajmniej na starszych sterownikach Siemensa.

BU
Jeśli chodzi o STL Siemensa, to nie jest to nic hardkorowego. Widziałem dużo programów napisanych w samym STL, ale częściej na S5 niż na S7. Pewnie dlatego, że Siemens jest lekko upośledzony. Inne firmy mają przyjemne FBD.
somekind
@jacek.placek: chyba przestraszyłeś kolegę i nie dowiemy się już niczego. :(
JP
Mam wrażenie, że już się wszystkiego dowiedzieliśmy :) 30% objętości kodu mniej i cośtam cośtam.
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
1

W Visual Studio podczas debugowania można normalnie oglądać wykonywany kod binarny (i jego odpowiednik w asemblerze), również dla programów pisanych w C#.
Nie trzeba nic wiedzieć o IL ani nawet o jego istnieniu.

v.png

Z tym, że oglądanie wygenerowanego asemblera w wersji debug trochę mija się z celem, bo widzimy wersję niezoptymalizowaną kodu.
Jeśli chcemy zobaczyć co kompilator jest rzeczywiście w stanie z naszym kodem zrobić, trzeba debugować wersję release programu oraz wyłączyć w ustawieniach Visuala opcje "Suppress JIT optimization on module load" i "Enable Just My Code".
Jednak wtedy debugger potrafi zachowywać się dziwnie.

  • v.png (68 KB) - ściągnięć: 240
edytowany 3x, ostatnio: Azarien
0

Oglądanie tego w ogóle mija się z celem . C# to nie jest niezarządzany kod C++ .
Z tego nic kompletnie nie wyczytasz . Co innego kod IL.

1

Kod z optymalizacją i bez optymalizacji .

Gdybym optymalizował ręcznie kod to prawdopodobnie zrobiłbym to identycznie albo prawie identycznie.

Kopiuj
using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Podaj pierwszą liczbę : ");
            int a = int.Parse(Console.ReadLine());

            Console.Write("Podaj drugą liczbę : ");
            int b = int.Parse(Console.ReadLine());

            if (a > b) Console.WriteLine($"{a} > {b}");
            else
            Console.WriteLine($"{a} < {b}");
        }
    }
}

kod metody main bez optymalizacji kod IL:

Kopiuj
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       112 (0x70)
  .maxstack  3
  .locals init ([0] int32 a,
           [1] int32 b,
           [2] bool V_2)
  IL_0000:  nop
  IL_0001:  ldstr      bytearray (50 00 6F 00 64 00 61 00 6A 00 20 00 70 00 69 00   // P.o.d.a.j. .p.i.
                                  65 00 72 00 77 00 73 00 7A 00 05 01 20 00 6C 00   // e.r.w.s.z... .l.
                                  69 00 63 00 7A 00 62 00 19 01 20 00 3A 00 20 00 ) // i.c.z.b... .:. .
  IL_0006:  call       void [mscorlib]System.Console::Write(string)
  IL_000b:  nop
  IL_000c:  call       string [mscorlib]System.Console::ReadLine()
  IL_0011:  call       int32 [mscorlib]System.Int32::Parse(string)
  IL_0016:  stloc.0
  IL_0017:  ldstr      bytearray (50 00 6F 00 64 00 61 00 6A 00 20 00 64 00 72 00   // P.o.d.a.j. .d.r.
                                  75 00 67 00 05 01 20 00 6C 00 69 00 63 00 7A 00   // u.g... .l.i.c.z.
                                  62 00 19 01 20 00 3A 00 20 00 )                   // b... .:. .
  IL_001c:  call       void [mscorlib]System.Console::Write(string)
  IL_0021:  nop
  IL_0022:  call       string [mscorlib]System.Console::ReadLine()
  IL_0027:  call       int32 [mscorlib]System.Int32::Parse(string)
  IL_002c:  stloc.1
  IL_002d:  ldloc.0
  IL_002e:  ldloc.1
  IL_002f:  cgt
  IL_0031:  stloc.2
  IL_0032:  ldloc.2
  IL_0033:  brfalse.s  IL_0053
  IL_0035:  ldstr      "{0} > {1}"
  IL_003a:  ldloc.0
  IL_003b:  box        [mscorlib]System.Int32
  IL_0040:  ldloc.1
  IL_0041:  box        [mscorlib]System.Int32
  IL_0046:  call       string [mscorlib]System.String::Format(string,
                                                              object,
                                                              object)
  IL_004b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0050:  nop
  IL_0051:  br.s       IL_006f
  IL_0053:  ldstr      "{0} < {1}"
  IL_0058:  ldloc.0
  IL_0059:  box        [mscorlib]System.Int32
  IL_005e:  ldloc.1
  IL_005f:  box        [mscorlib]System.Int32
  IL_0064:  call       string [mscorlib]System.String::Format(string,
                                                              object,
                                                              object)
  IL_0069:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_006e:  nop
  IL_006f:  ret
} // end of method Program::Main

kod IL po optymalizacji

Kopiuj
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       102 (0x66)
  .maxstack  3
  .locals init ([0] int32 a,
           [1] int32 b)
  IL_0000:  ldstr      bytearray (50 00 6F 00 64 00 61 00 6A 00 20 00 70 00 69 00   // P.o.d.a.j. .p.i.
                                  65 00 72 00 77 00 73 00 7A 00 05 01 20 00 6C 00   // e.r.w.s.z... .l.
                                  69 00 63 00 7A 00 62 00 19 01 20 00 3A 00 20 00 ) // i.c.z.b... .:. .
  IL_0005:  call       void [mscorlib]System.Console::Write(string)
  IL_000a:  call       string [mscorlib]System.Console::ReadLine()
  IL_000f:  call       int32 [mscorlib]System.Int32::Parse(string)
  IL_0014:  stloc.0
  IL_0015:  ldstr      bytearray (50 00 6F 00 64 00 61 00 6A 00 20 00 64 00 72 00   // P.o.d.a.j. .d.r.
                                  75 00 67 00 05 01 20 00 6C 00 69 00 63 00 7A 00   // u.g... .l.i.c.z.
                                  62 00 19 01 20 00 3A 00 20 00 )                   // b... .:. .
  IL_001a:  call       void [mscorlib]System.Console::Write(string)
  IL_001f:  call       string [mscorlib]System.Console::ReadLine()
  IL_0024:  call       int32 [mscorlib]System.Int32::Parse(string)
  IL_0029:  stloc.1
  IL_002a:  ldloc.0
  IL_002b:  ldloc.1
  IL_002c:  ble.s      IL_004a
  IL_002e:  ldstr      "{0} > {1}"
  IL_0033:  ldloc.0
  IL_0034:  box        [mscorlib]System.Int32
  IL_0039:  ldloc.1
  IL_003a:  box        [mscorlib]System.Int32
  IL_003f:  call       string [mscorlib]System.String::Format(string,
                                                              object,
                                                              object)
  IL_0044:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0049:  ret
  IL_004a:  ldstr      "{0} < {1}"
  IL_004f:  ldloc.0
  IL_0050:  box        [mscorlib]System.Int32
  IL_0055:  ldloc.1
  IL_0056:  box        [mscorlib]System.Int32
  IL_005b:  call       string [mscorlib]System.String::Format(string,
                                                              object,
                                                              object)
  IL_0060:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0065:  ret
} // end of method Program::Main
edytowany 1x, ostatnio: Ktos
somekind
@Pixello @msm - coś do śmiechu dla Was. ;)
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 23 godziny
0

Zimny Krawiec:
To czyste marnowanie czasu. Zysk dla użytkownika końcowego jest zerowy, albo ujemny, bo czas spędzony na oszczędzaniu kilku bajtów można przeznaczyć na poprawienie funkcjonalności czy wydajności (poprzez np polepszenie złożoności obliczeniowej, a nie samej stałej w złożoności).

Jeśli lubisz siedzieć w IL to jest fajne zadanie dla ciebie: https://github.com/oracle/graal/issues/349 :)


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
somekind
Umiejętność przestawienia kompilacji z Debug na Release raczej mu nie pomoże w implementacji tego ticketa. ;)
Wibowit
ale ma chłopak zapał i wydaje mu się, że jest lepszy bo grzebie w bajtkodzie, więc może by coś sklecił
somekind
Ale on nie grzebie tylko trolluje. Pierwszy kod to kompilacja debug, a drugi release, żadnej inwencji twórczej tu nie było. :)
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
0
Chory Lew napisał(a):

Oglądanie tego w ogóle mija się z celem . C# to nie jest niezarządzany kod C++ .
Z tego nic kompletnie nie wyczytasz . Co innego kod IL.

Jak to "nic nie wyczytasz"? To jest rzeczywiście wykonywany kod. Jak kogoś nie interesuje to niech nie ogląda, ale… moim zdaniem czytanie IL ma jeszcze mniejszy sens.

0

To weź wstaw jakiś krótki programik - 2 -3 linijki kodu , listing tego twojego asemblera
i omów co on zawiera . Bo ja odnośnie IL mogę ci wszystko wytłumaczyć co i jak ,

Pozdrawiam serdecznie ;)

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 23 godziny
0

Ja czasami czytam bajtkod Javowy, ale tylko jak chcę się upewnić jak coś tam działa pod spodem. Nie czytam bajtkodu po to, by ocenić jak dobrą (czy nie do końca dobrą) robotę zrobił kompilator.

Nie widzę sensu poprawiania bajtkodu skoro JIT w JVMie radzi sobie z optymalizacją (względnie) skomplikowanych abstrakcji na poziomie języka: dyskusja nad foreach w .NET i porównanie do Javy


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
0
Zimny Krawiec napisał(a):

Bo ja odnośnie IL mogę ci wszystko wytłumaczyć co i jak ,

Tylko że… po co czytać IL, skoro masz ten sam kod w C#? :-)
Chyba tylko żeby zobaczyć na co przekłada się jakiś lukier składniowy, ot choćby ten foreach.

0

OK . Weźmy pod lupę instrukcję foreach na przykładzie typu List<T> , żeby lepiej zrozumieć jak to hula ;)

Kopiuj
using System;
using System.Collections.Generic;
namespace ConsoleApp40
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista = new List<int>(5);
            lista.Add(1);
            lista.Add(2);
            lista.Add(3);
            lista.Add(4);
            lista.Add(5);

            foreach (int item in lista)
            {
                Console.Write(item + ",");
            }
        }
    }
}

Otrzymujemy kod IL:

Kopiuj
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       106 (0x6a)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> lista,
           [1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_1,
           [2] int32 item)
  IL_0000:  ldc.i4.5
  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor(int32)
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.1
  IL_0009:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
  IL_000e:  ldloc.0
  IL_000f:  ldc.i4.2
  IL_0010:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
  IL_0015:  ldloc.0
  IL_0016:  ldc.i4.3
  IL_0017:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
  IL_001c:  ldloc.0
  IL_001d:  ldc.i4.4
  IL_001e:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
  IL_0023:  ldloc.0
  IL_0024:  ldc.i4.5
  IL_0025:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
  IL_002a:  ldloc.0
  IL_002b:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
  IL_0030:  stloc.1
  .try
  {
    IL_0031:  br.s       IL_0050
    IL_0033:  ldloca.s   V_1
    IL_0035:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
    IL_003a:  stloc.2
    IL_003b:  ldloc.2
    IL_003c:  box        [mscorlib]System.Int32
    IL_0041:  ldstr      ","
    IL_0046:  call       string [mscorlib]System.String::Concat(object,
                                                                object)
    IL_004b:  call       void [mscorlib]System.Console::Write(string)
    IL_0050:  ldloca.s   V_1
    IL_0052:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
    IL_0057:  brtrue.s   IL_0033
    IL_0059:  leave.s    IL_0069
  }  // end .try
  finally
  {
    IL_005b:  ldloca.s   V_1
    IL_005d:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
    IL_0063:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0068:  endfinally
  }  // end handler
  IL_0069:  ret
} // end of method Program::Main

Czyli zamiast instrukcji forach możemy napisać tak : ( możemy też zrezygnować z jednej zmiennej )

Kopiuj
using System;
using System.Collections.Generic;
namespace ConsoleApp40
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista = new List<int>(5);
            lista.Add(1);
            lista.Add(2);
            lista.Add(3);
            lista.Add(4);
            lista.Add(5);
            using (List<int>.Enumerator item = lista.GetEnumerator())
            {
                while (item.MoveNext())
                {
                    Console.Write(item.Current + ",");
                }
            }
        }
    }
}
edytowany 1x, ostatnio: Patryk27
0

albo krócej :. Myślę,że nikt się chyba nie zgorszy ;)

Kopiuj
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
          
            using (List<int>.Enumerator item = new List<int> { 1, 2, 3, 4, 5 }.GetEnumerator())
            {
                while (item.MoveNext())
                {
                    Console.Write(item.Current + ",");
                }
            }
        }
    }
}
edytowany 1x, ostatnio: Patryk27
Patryk27
Pamiętaj o umieszczaniu kodu w odpowiednich znacznikach.
JP
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 miesiące
  • Postów:1065
0

Ale coś z tego wynika czy tylko potwierdzasz słowa @Azarien?

Możemy używać enumeratorow i używaliśmy zanim wynaleziono koło i inne różne rzeczy.

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

@Mistrzowski Lew: czyli potwierdziłeś, że foreach jest lukrem składniowym na GetEnumerator ;-)


Azarien
ale to nie jest jakaś wiedza tajemna… ;-)
0

Wiem że to nie jest żadna wiedza tajemna . Wyluzujcie chopaki ;)

JP
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 miesiące
  • Postów:1065
0

Spoko. Hobbystycznie to sobie można sobie oglądać jak co działa ale w normalnej pracy to strata czasu. Ja jestem często po tej stronie co płaci i zwykle dość nerwowo reaguje na takie tematy bo dla mnie to strata czasu czyli pieniędzy.
Kiedyś znajomy pisał własny parser do XMl-a. A było to w czasach jak już był LINQ a On o tym nie wiedział. Sporo niepotrzebnych godzin i trzeba się było pożegnać.

Azarien
Nie chcę się wtrącać, ale to „trzeba się było pożegnać” brzmi bardzo wątpliwie.
Azarien
bo brzmi jak wyrzucenie człowieka tylko dlatego że robił coś niepotrzebnie, nawet jeśli robił to dobrze. no chyba że to był już któryś raz a człowiek się okazał niereformowalny…
JP
Dłuższa historia ale ja jestem misiem i mnie nie stać na takie rzeczy. To był zewnętrzny kontraktor i miał rozwiązać zupełnie inny problem. Sporo w tym mojej winy bo powinienem to lepiej kontrolować.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)