Sa utilizam bubble sort …
M-am gandit sa ma mai joc putin cu bubble sort-ul, sa-l folosesc in cadrul unei anumite probleme. Problema care mi-a venit in minte este urmatoarea : Sa se scrie o functie care primeste ca parametru un numar natural si care returneaza cel mai mare numar care se poate forma cu cifrele sale . Algoritmul banal cu care se rezolva aceasta problema este urmatorul:
-retinem cifrele numarului intr-un vector
-le ordonam
-compunem noul numar
Am implementat totul in ASM desigur. Pentru a nu mai recurge la fel de fel de artificii, am organizat vectorul in felul urmator:
v[0] - numarul de cifre
v[1] ... v[v[0] - cifrele numarului
Bineinteles, am modificat usor bubble-sort-ul ( cel scris de mine avea nevoie de 2 variabile , un pointer catre primul element al vectorului, v[0] , si numarul de elemente ... cateva modificari minore si a fost gata. O alta problema care mi-a atras atentia la bubble sort a fost urmatoarea : ce se intampla daca exista un singur element in vector ? Am vrut sa merg la f**** masa si sa-l las asa, dar atunci cand compara v[i] cu v[i+1], sare la o adresa la care nu se gaseste nimic ... eroare
... am prevazut acest caz in functia maxim() . Este cel mai lung programel scris de mine in ASM ( vreo 90 linii de cod ) ... Sper sa nu mai am placerea sa scriu programe atat de lungi in ASM, e foarte dificil sa caut erori, chiar si cu ajutorul debugger-ului ... Iata codul...
-
#include <iostream>
-
using namespace std;
-
-
void bubble_sort(int*)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[eax]
-
add eax,4
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
jmp continua
-
interschimbare:
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
continua:
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica
-
cmp ecx,1
-
je bucla_mare
-
}
-
}
-
-
int maxim(int)
-
{
-
int v[12];
-
_asm
-
{
-
mov eax,[ebp+8]
-
cmp eax,10
-
jb exceptie
-
jmp continua
-
exceptie:
-
mov ecx,eax
-
jmp stop2
-
continua:
-
mov ebx,10
-
mov ecx,0
-
lea esi,v
-
add esi,4
-
bucla1:
-
mov edx,0
-
cmp eax,0
-
je stop1
-
div ebx
-
inc ecx
-
mov [esi],edx
-
add esi,4
-
jmp bucla1
-
stop1:
-
lea eax,v
-
mov [eax],ecx
-
push eax
-
call bubble_sort
-
add esp,4
-
-
mov ecx,0
-
mov eax,1
-
lea esi,v
-
mov ebx,[esi]
-
add esi,4
-
bucla2:
-
cmp ebx,0
-
je stop2
-
push ecx
-
mov ecx,[esi]
-
mov edx,0
-
push eax
-
mov edi,eax
-
mov eax,1
-
mul edi
-
mul ecx
-
pop edx
-
pop ecx
-
push edx
-
add ecx,eax
-
pop eax
-
mov edi,10
-
mul edi
-
dec ebx
-
add esi,4
-
jmp bucla2
-
stop2:
-
mov eax,ecx
-
}
-
}
-
-
int main()
-
{
-
int x;
-
cin>>x;
-
cout<<maxim(x)<<endl;
-
system("pause");
-
return 0;
-
}
O mica problema in ASM … de Craciun
Pentru ca tot era Craciunul si nu aveam ce face, m-am apucat de o mica problema in ASM ... am apelat la un coleg de facultate,Alex D., care mi-a dat urmatoarea problema : Sa se ordoneze un vector de numere naturale dupa numarul de biti necesari pentru a le scrie in baza 2 ... aveam deja bubble sort-ul implementat in asm ... Am procedat in felul urmator: stiam ca bubble sort compara, la un moment dat cate 2 elemente si verifica daca unul e mai mare ca celalalt. In loc de aceasta condiitie, eu trebuia sa aflu daca numarul de biti al primului e mai mare ca numarul de biti al celui de-al doilea... ca sa evit o seara "plina", am scris o alta functie, tot in asm , care imi returneaza numarul de biti pentru un numar. De aici totul a fost simplu ... ba nu ! Am stat o ora intreaga, uitandu-ma dupa pop-uri, push-uri, unele adrese se pierdeau, o adevarata dezordine... noroc cu prietenul meu AndreiASM ( numele spune tot
), care m-a ajutat cu diverse chestii tehnice pe care nu aveam de unde sa le cunosc ( apelarea unei functii cu parametri, etc. ) . In cele din urma, a rezultat codul de mai jos, care "merge", dar nu am absolut niciun chef sa ma mai bag pe el in caz ca gasesc vreo eroare...
-
#include <stdio.h>
-
#include <iostream>
-
using namespace std;
-
-
-
int nr_biti(int)
-
{
-
_asm
-
{
-
mov eax,[ebp+8]
-
cmp eax,0
-
je final
-
mov ebx,0
-
bucla:
-
cmp eax,0
-
je stop
-
inc ebx
-
shr eax,1
-
jmp bucla
-
stop:
-
mov eax,ebx
-
jmp stop2
-
final:
-
mov ebx,1
-
jmp stop
-
stop2:
-
-
}
-
}
-
-
void bubble_sort(int*,int)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[ebp+12]
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
-
push dword ptr[eax]
-
push dword ptr[edx]
-
-
push eax
-
-
mov edi,eax
-
-
push dword ptr[edx]
-
call nr_biti
-
mov [edx],eax
-
add esp,4
-
-
push dword ptr[edi]
-
call nr_biti
-
mov [edi],eax
-
add esp,4
-
-
pop eax
-
push ecx
-
mov ecx,[edi]
-
mov [eax],ecx
-
pop ecx
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
cmp esi,[edx]
-
jle nu_e
-
-
interschimbare:
-
pop dword ptr[edx]
-
pop dword ptr[eax]
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
nu_e: pop dword ptr[edx]
-
pop dword ptr[eax]
-
jmp continua
-
-
continua:
-
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica
-
cmp ecx,1
-
je bucla_mare
-
}
-
}
-
-
int main()
-
{
-
int v[100],n,i;
-
cin>>n;
-
for(i=0;i<n;i++) cin>>v[i];
-
bubble_sort(v,n);
-
for(i=0;i<n;i++) cout<<v[i]<<' ';
-
system("pause");
-
return 0;
-
}
Use the stack , Luke !
Lucrez de foarte putin timp timp in ASM si , cum imi sta mie mai bine, imi place sa ma complic al naibii de tare cand rezolv o problema... de exemplu, azi m-am gandit la urmatoarea problema in ASM : se da un vector de numere intregi. Sa se scrie o functie in ASM care inverseaza elementele vectorului .
Ok . Bag in registrul eax adresa elementului curent, calculez cati bytes trebuie sa sar ca sa ajung la ultimul element, fac o bucla, sar la elementul al doilea, calculez cati bytes am nevoie sa sar la penultimul ... etc., nervi, pana la urma adaug un sub edx,ecx ... minune, merge. De ce? Nu ma mai intereseaza... Merge si atat. Iata minunatul cod:
-
void inversare(int*,int)
-
{
-
_asm
-
{
-
mov ecx,0
-
mov ebx,[ebp+12]
-
shr ebx,1
-
dec ebx
-
bucla:
-
mov eax,[ebp+8]
-
-
push ecx
-
shl ecx,2
-
add eax,ecx
-
pop ecx
-
-
mov edx,[ebp+12]
-
dec edx
-
sub edx,ecx
-
sub edx,ecx
-
shl edx,2
-
-
push eax
-
add eax,edx
-
mov edx,eax
-
pop eax
-
-
push dword ptr [eax]
-
push dword ptr [edx]
-
pop dword ptr [eax]
-
pop dword ptr [edx]
-
-
cmp ecx,ebx
-
jne continua
-
cmp ecx,ebx
-
je stop
-
continua:
-
inc ecx
-
jmp bucla
-
stop:
-
}
-
}
Ok... , ma minunam si eu de cat de frumos e codul asta ... ma simteam mandru... USE THE STACK LUKE... mi-am adus aminte de Star Wars ... si de o mica chestie numite STIVA... care avea interesenta proprietate ca ultimul intrat era primul iesit . Sa vezi si sa nu crezi ... exact ce-mi trebuia mie .
Mi-am tras o palma peste cap, am pornit alt proiect, am scris repede codul, a rezultat cel de mai jos. Elegant, simplu, fara shiftari de biti sau alte magarii ...
-
void inverseaza2(int*,int)
-
{
-
_asm
-
{
-
mov eax,[ebp+8]
-
mov ecx,[ebp+12]
-
mov edx,0
-
bucla:
-
cmp edx,ecx
-
je final
-
push dword ptr [eax]
-
add eax,4
-
inc edx
-
jmp bucla
-
final:
-
mov eax,[ebp+8]
-
mov edx,0
-
bucla2:
-
cmp edx,ecx
-
je final2
-
pop dword ptr [eax]
-
add eax,4
-
inc edx
-
jmp bucla2
-
final2:
-
}
-
}
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
De acum incolo voi folosi stiva !
Bubble Sort - ASM
Astazi am reusit , cu ajutor ce-i drept ( din partea prof. meu de arhitectura ), sa implementez ultra-performantul, ultra-schimbistul si nemaipomenitul Bubble Sort . Il pun aici, in speranta ca mai exista cineva care este interesat de ASM ...
-
void bubble_sort(int*,int)
-
{
-
_asm
-
{
-
bucla_mare:
-
mov ecx,0
-
mov eax,[ebp+8]
-
mov ebx,[ebp+12]
-
bucla_mica:
-
mov edx,eax
-
add edx,4
-
mov esi,[eax]
-
cmp esi,[edx]
-
ja interschimbare
-
jmp continua
-
interschimbare:
-
push dword ptr [edx]
-
push dword ptr [eax]
-
pop dword ptr [edx]
-
pop dword ptr [eax]
-
mov ecx,1
-
jmp continua
-
continua:
-
add eax,4
-
dec ebx
-
cmp ebx,1
-
jne bucla_mica
-
cmp ecx,1
-
je bucla_mare
-
}
-
}
Primul parametru al functiei este un pointer catre primul element al vectorului, al doilea parametru reprezentand numarul de elemente din vector .
Functia se poate apela in felul urmator:
-
int v[100],n,i;
-
citeste n
-
citeste componentele vectorului
-
bubble_sort(v,n);
Functie cu numar variabil de parametri - C/C++/ASM
In topicul anterior am vorbit despre modurile in care putem extrage parametrii de pe stiva. Cum in C nu puteam sti exact cati parametri sa luam, am apelat la 2 artificii . Ori stiam cati parametri urmau sa apara, ori stiam unde sa ne oprim . C/C++ -ul nu permite in mod normal sa cunoastem numarul de parametri cu care am apelat o functie ( cu numar variabil de parametri ) . Insa acest lucru se poate rezolva cu ajutorul ASM. Nu vom mai folosi stdarg.h , prin urmare nu mai avem nevoie de acel prim parametru static al functiei. Urmatoarea functie afiseaza toti parametrii cu care a fost apelata...
-
void functie(...)
-
{
-
unsigned char nr_parametri;
-
int *parametru,i;
-
-
_asm
-
{
-
mov eax,[ebp+4]
-
add eax,2
-
mov al,[eax]
-
shr al,2
-
mov nr_parametri,al
-
mov parametru,ebp
-
add parametru,8
-
}
-
-
for(i=0;i<nr_parametri;i++)
-
cout<<parametru[i]<<" ";
-
}
Acum,in vectorul parametru, avem toti parametrii si ne putem juca dupa cum dorim cu ei ... va ramane ca tema sa modificati functia astfel incat sa calculeze suma![]()
Functie cu numar variabil de parametri - C/C++
Ok, am realizat acest lucru in C#, am vazut cat de simplu se poate realiza, intrebarea se pune in felul urmator: mai putem realiza la fel de usor acest lucru si in C/C++ ?
Putina teorie , pentru inceput. Atunci cand apelam o functie cu anumiti parametri, acestia sunt luati de pe stiva. Daca avem 2 parametri, luam 2 parametri de pe stiva, daca avem 3, luam 3, dar daca avem un numar variabil de parametri , cati vom lua de pe stiva? Se profileaza astfel urmatoarele probleme:
1.O functie care sa ia de pe stiva exact cati parametrii cu care a fost apelata functia
2.O functie care sa stie cumva unde sa se opreasca cand cauta parametrii.
Prima problema va fi discutata separat intr-un alt topic ( fiind mai dificil de inteles ).
In primul rand, in C/C++ numarul variabil de parametri se pune in evidenta prin utilizarea "..." ( trei puncte, foarte sugestiv ). Problema este ca nu putem avea direct un numar variabil de parametri, ci neaparat un parametru care este stabil. Sa trecem in continuare la modul in care putem lua parametrii de pe stiva. Avem doua optiuni. Ori stim de dinainte cati parametri vom avea , ori stim cand sa ne oprim. De exemplum, pentru calcularea sumei a n numere, putem apela in felul urmator:
-
cout<<suma(5,1,2,3,4,7);
Primul parametru,5, reprezinta numar parametrilor ( "variabil"
) .
-
cout<<suma(1,2,3,4,7,0);
Ultimul parametru l-am pus 0 ( element neutru la adunare ) . Atunci cand dam de el, stim sa ne oprim ( putem pune absolut orice care sa se potriveasca problemei noastre , doar trebuie sa stim cand sa ne oprim ).Sa scriem doua functii care sa implementeze cele doua concepte. Sa incepem cu prima functie, cea in care cunoastem cati parametri vom avea:
-
int functie(int prim,...)
-
{
-
int contor=1,val,suma=0;
-
va_list marker;
-
va_start(marker,prim);
-
while(contor<=prim)
-
{
-
val=va_arg(marker,int);
-
suma+=val;
-
contor++;
-
}
-
return suma;
-
}
Sa scriem aceeasi functie, care de data asta se va opri cand va gasi parametrul 0 :
-
int functie(int prim,...)
-
{
-
int val=1,suma=0;
-
va_list marker;
-
va_start(marker,prim);
-
suma+=prim;
-
while(val!=0)
-
{
-
val=va_arg(marker,int);
-
suma+=val;
-
}
-
return suma;
-
}
Pentru ca functiile de mai sus sa functioneze, trebuie sa includeti linia:
-
#include <stdarg.h>
Functie cu numar variabil de parametri - C#
Sa continuam discutia despre numarul parametri cu acesta noua problema , o functie cu numar variabil de parametri. Ce inseamna acest lucru mai exact ? In mod normal, pana acum cand scriati o functie care primea parametri, scriati in felul urmator:
-
tip nume(tip nume,tip nume ... tip,nume)
-
{}
Ce se intampla daca nu stiu de dinainte de cati parametri voi avea nevoie ? Sa zicem ca as dori sa apelez in felul urmator:
-
...
-
functie(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);
Probabil ca unii dintre voi deja s-au apucat sa declare parametrii (
) . Sau sa luam un alt exemplu, mai practic. Ce face urmatoarea functie?
-
int a,b;
-
a=10;
-
b=20;
-
Console.Write("a={0} si b={1}", a, b);
Sau , mai general, urmatorul exemplu:
-
int a = 1;
-
string b = "text";
-
float c=1.23f;
-
double d=11111111000;
-
Console.Write("a={0} si b={1} si c={2} si d={3}", a, b, c, d);
Exista situatii, unele mai practice decat altele, in care nu stim de la inceput cati parametri va avea functia. Mai mult de atat, poate stim de dinainte cati parametri va avea functia, dar nu stim care este tipul lor. Un caz "celebru" este cel al programatorului anonim,amator de Coca-Cola, cu ochii inrositi, care isi doreste sa aiba o functie pentru care nu stie nici numarul nici tipul parametrilor ( cu toate ca, in practica, asa ceva nu exista , utilizatorul intotdeauna va introduce datele necesare ). Pot spune ca este mai mult un "moft" ( interesant moft totusi ) .
Din fericire, C#-ul ne rezolva toate probleme, punandu-le la dispozitie o metoda speciala de transmitere a parametrilor.Dupa cum probabil stiti din C++, putem transmite parametri prin valoare sau prin referinta. C#-ul introduce o noua modalitate de transmitere, special realizata pentru lucrul cu numarul variabil de parametri, si anume "params".
-
static void functie(params[] int parametri)
In acest exemplu, am specificat faptul ca functia primeste un numar variabil de parametri de tip "int". "Variabil", nu prea putem spune deoarece putem cunoaste numarul lor
-
int nr_parametri=parametri.Length;
Exemplu de program care apeleaza o functie cu un numar variabil de parametri de tip int si calculeaza suma lor:
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Text;
-
namespace Parametri
-
{
-
class Program
-
{
-
-
static int functie(params int[] x)
-
{
-
int suma = 0,i;
-
for (i = 0; i <x.Length; i++)
-
suma += x[i];
-
return suma;
-
-
}
-
-
-
static void Main(string[] param)
-
{
-
Console.WriteLine(functie(1, 2, 3, 4));
-
Console.Read();
-
-
}
-
}
-
}
Acum , sa luam celalalt caz, in care nu stim nici ce tip au parametrii . Pentru acest caz, C#-ul de pune la dispozitie un tip generic, numit "object" . Aceste poate fi de orice tip ( int, string, char,float,bool, etc. ) .Antetul functiei cu numar variabil de parametri de tip variabil va fi urmatorul:
-
static void functie(params object[] x)<