profil

C++ - wykład 4/4

poleca 87% 102 głosów

Treść
Grafika
Filmy
Komentarze





Wykład 4 - 3 godz

Zakres tematyczny

1. Łączenie procedur w różnych językach



Czasami przychodzi moment, kiedy programy napisane w języku C/C++ muszą wywołać programy napisane w innych językach, lub kiedy program napisany w innym języku musi wywołać funkcję napisaną w języku C/C++. Taki proces nazywany jest mixed-language programing- programowanie w mieszanych językach. Np. kiedy jakiś szczególny podprogram dostępny jest w języku innym niż C/C++, lub kiedy algorytm opisany jest w sposób bardziej naturalny w innym języku, występuje potrzeba użycia w programie, więcej niż jednego języka.

Na dzisiejszym wykładzie omówimy najważniejsze zasady mixed language programing.



Tworzenie wywołań w językach mieszanych

Programowanie w językach mieszanych MLP, sprowadza się do odwołań do funkcji, procedur lub podprogramów, w zależności od konwencji przyjętej dla danego języka. Np.:, BASIC-kowski moduł główny, może wykonywać specyficzne zadanie, które chciałby programista zaprogramować oddzielnie. Zamiast wywoływać jednak podprogram BASIC-kowski, decyduje się wywołać funkcję C.

Wywołanie funkcji napisanych w różnych językach polega na wywołaniu funkcji umieszczonych w różnych modułach. Zamiast kompilowania wszystkich modułów jednym kompilatorem, używa się różnych kompilatorów (różnych języków). Na marginesie należy tu zaznaczyć, iż uwaga ta dotyczy kompilatorów języków tego samego producenta. np. Microsoft czy też Borland, co związane jest z różnicami w formatach modułów obj.

Dla powyższego przykładu oznacza to, że moduł główny kompilowany jest w kompilatorze BASIC, inny zbiór zawierający funkcję C kompilatorem C, a dopiero potem oba zbiory obj-towe linkowane są w jeden kod wynikowy.







Na rysunku powyżej widzimy wywołanie z poziomu języka BASIC funkcji prn() języka C, podobnej do podprogramu w języku BASIC. Są dwie istotne różnice pomiędzy tym wywołaniem mieszanym, z wywołanie pomiędzy dwoma BASIC-kowskimi modułami:

- podprogram prn jest zaimplementowany w języku C, używając standardu tego języka

- wykonanie wywołania w BASIC'u jest poprzedzone użyciem instrukcji DECLARE używającej słowa kluczowego CDECL do stworzenia kompatybilności z C.T a interfejsowa instrukcja, zmienia nazewnictwo i konwencje wywołań. Każdy język dostarcza swoich własnych form interfejsów.



Można wykonywać wywołania mieszane nie zważając na to, czy funkcje wywoływane z innych modułów zwracają wartości.



Językowe odpowiedniki dla wywołań funkcji (procedur, podprogramów)



Język Zwracająca wartość Nie zwracająca wartości

Asemblery procedure procedure

BASIC FUNCTION procedure Subprogram

C/C++ function void function

FORTRAN FUNCTION SUBROUTINE

PASCAL Function Procedure



Jak widać z tabelki moduł C może wykonać wołanie fortranowskiego SUBROUTINE, będącego odpowiednikiem void function z języka C, itp.



Wymagania dotyczące konwencji językowych

W mieszanym programowaniu, wywołujący program musi przestrzegać tych samych konwencji, jak program wywoływany. Konwencje te można pogrupować w następujące grupy:

-jak kompilator traktuje identyfikatory, włączając nazwy funkcji i zmiennych - konwencja nazewnictwa

-jak zaimplementowane jest wywołanie podprogramu - konwencja wywołań

-jak przekazywane są parametry - konwencja przesyłania parametrów.



Konwencja nazewnictwa

Zarówno program wywołujący jak i wywoływany podprogram, musza zgadzać się na płaszczyźnie nazw identyfikatorów. Identyfikatory mogą odnosić się do podprogramów (funkcji, procedur) lub zmiennych mających publiczny lub globalny zakres. Każdy język zmienia nazwy identyfikatorów.

Termin "konwencja nazewnictwa" odnosi się do sposobu w jaki procesor zmienia nazwy podprogramów zanim umieści je w zbiorze obj-towym. Każdy język zmienia te nazwy na swój sposób. Programista może wybierać pomiędzy różnymi konwencjami nazewnictwa, aby upewnić się że nazwy w wywołującym programie zgadzają się z tymi w programie wywoływanym. Jeśli nazwy wywoływanego podprogramu są przechowywany w każdym zbiorze obj-towym inaczej, wtedy linker nie byłby w stanie znaleźć powiązań. Będzie wtedy raportował o nierozerwalnym zewnętrznych powiązaniach.

Większość kompilatorów języka ładuje kod maszynowy do zbioru obj-towego. Przechowywane tam też są nazwy publicznych podprogramów i zmiennych. Linker może wtedy porównać nazwę podprogramu wywoływanego w jednym module z nazwą podprogramów zdefiniowanych w innym module i rozpoznaje powiązania. Nazwy tworzone są zgodnie ze standardem znaków ASCII



BASIC, FORTRAN i PASCAL używają podobnej konwencji nazewnictwa. Tłumaczą każdą literę na duże znaki.

Każdy język rozpoznaje różną liczbę znaków. I tak np. FORTRAN rozpoznaje pierwszych 31 znaków w nazwie (chyba że nazwy identyfikatorów są obcinane - ustawieniem opcji $TRUNCATE), Pascal pierwsze 8, Basic pierwszych 40 znaków. Jeśli nazwa zawiera więcej znaków niż dopuszcza dany kompilator, pozostałe znaki nie są po prostu umieszczane w zbiorze obj-towym.

Kompilatory języka C nie zamieniają każdej litery na duże. Nazwa każdego podprogramu uzupełniana jest od przodu znakiem podkreślenia. Kompilator tego języka rozpoznaje 31 znaków nazwy identyfikatora (32 włączając znak podkreślenia). Używając odpowiednich opcji kompilatora (np./H) można zmienić liczbę rozpoznawanych znaków.

Kompilator języka C++..................................................... Rozpoznaje pierwszych 247 znaków nazwy.

Słowa kluczowe języków programowania mieszanego zajmują się automatycznie różnicami w konwencji nazewnictwa tak długo jak przestrzegane są dwie zasady:

1. ograniczać nazewnictwo identyfikatorów do 6 znaków, jeśli:

a). włączane procedury kompilowane były kompilatorem Fortran <5.0

b) włączane procedury kompilowane były kompilatorem z opcją /4Yt lub w metakomendą $TRUNCATE

2. nie używać opcji linkera /NOIGNORECASE. Z modułami C/C++ oznacza to, że w czasie programowania nie można liczyć na rozpoznawanie dużych i małych liter.



Jeśli używamy opcji /Gc (generate Pascal-style function call) podczas kompilacji , lub deklarujemy funkcję lub zmienną ze słowem kluczowym __pascal, kompilator przekształca nazwy identyfikatorów na duże litery.







Zwróćmy uwagę, że np. kompilator Basci'u wprowadza poprzedzający nazwę funkcji znak podkreślenia do zbioru obj-towego, ponieważ słowo CDECL każe kompilatorowi Basic'u używać konwencji nazewnictwa charakterystycznej dla języka C. Powoduje również zamianę wszystkich znaków nazw na małe litery (co prawda nie jest to konwencja przyjęta dla języka C, ale uznawana jest powszechnie przy pisania programów w tym języku).







Konwencja wywołań

Termin ten odnosi się do sposobu w jaki kompilator realizuje wywołania. Wybór konwencji polega na zrealizowaniu odpowiedniej wygenerowanej przez kompilator instrukcji maszynowej wykonującej (i powracającej z ) wywołanie funkcji, procedury lub subroutine.

................

Wybór konwencji wywołań oddziaływuje na program w trzech aspektach:

1. określenia kolejności w jakiej zostaną przesłane parametry do innego podprogramu. Można to określić przy pomocy specjalnych deklaracji lub używając instrukcji interfejsowych, dotyczących programowania mieszanego. Konwencje te dotyczą podprogramu wywołującego

2. dla podprogramu wywoływanego będzie to określenie kolejności odbierania parametrów do nich przesyłanych. W większości programów sposób odbierania parametrów określany jest w nagłówkach podprogramów, jednak np. Basic zawsze używa swojego własnego sposobu odbierania parametrów.

3. oba podprogramy: wywołujący i wywoływany muszą zgadzać się jeśli chodzi o odpowiedzialność za uporządkowanie stosu w czasie usuwania parametrów.



Innymi słowy: każde wywołanie podprogramu używa pewnej konwencji wywołań. Każdy nagłówek podprogramu zawiera określenie lub ustawienie innej konwencji. Musza być one kompatybilne dla obu podprogramów. W każdym języku z wyjątkiem Basica jest możliwość zmiany tej konwencji, w momencie wywołania lub przy pomocy deklaracji w wywoływanym podprogramie. Zwykle jednak łatwiej jest dostosować konwencje wywoływanego programu.

Języki C++, Basic, Fortran i Pascal używają tego samego standardu wywołań, natomiast język C ma odmienną.

Jeśli chodzi o uporządkowanie stosu, to języki :C++, Pascal, Fortran i Basic przesyłają parametry inaczej jak język C. Składają one parametry na stos w kolejności icj pojawienia się w kodzie źródłowym np. Basic-kowe wywołania:

CALL Calc(A,B)

składuje na stosie parametr A, przed parametrem B. W tej konwencji przyjęte jest też, że za uporządkowanie stosu odpowiada procedura wywołana bezpośrednio przed przejęciem sterowania przez wywołujący moduł.

W konwencji C parametry przesyłane są w odwrotnej kolejności. Np. wywołanie funkcji C:

calc(a,b)

składuje na stosie najpierw parametr b, a potem dopiero a. W przeciwieństwie od innych języków wysokiego poziomu, konwencja języka C określa, że podprogram wywołujący porządkuje stos natychmiast po zwrócenia sterowania przez wywoływany podprogram.

Konwencja wywołań Basic'u, Pascal'a i Fotran'u sprawia, że kod obj-towy jest mniejszy niż C. Jednak Z kolei jak państwo wiecie konwencja języka C umożliwia wywołanie funkcji ze zmienną liczba parametrów. Jeśli w języku C++ używamy wywołania funkcji ze zmienna liczbą argumentów, funkcja używa automatycznie konwencji wywołań dla języka C.

Należy unikać używania słowa kluczowego __fastcall lub opcji /Gr przesyłającej parametry do rejestrów, Tworzy to niekompatybilności z programami napisanymi w innych językach.



Konwencja przesyłania parametrów

Oprócz zgodności konwencji nazewnictwa i wywołań, programy muszą zgadzać się co do sposobu w jakim przesyłane są parametry. Zapewnia to poprawną transmisję danych i prawidłowe efekty pracy programu. Jak państwo wiecie w języku C były dwa sposoby przesyłania parametrów: poprzez wartość i adres, dla C++ doszło jeszcze przesyłania przez referencje. Z wyjątkiem języka Basic który przyjął jedynie przesyłanie przez adres (typu near - w obrębie jednego segmentu), pozostałe języki mają możliwość wykorzystania takich samych sposobów przesyłania parametrów.

Kiedy programujemy w językach mieszanych należy:

- upewnić się, czy podprogram wywołujący i wywoływany używają tego samego sposobu przesyłania parametrów. Każdy język ma mechanizmy umożliwiające zmianę tych metod.

Każdy język dostosowuje określoną metodę przesyłania parametrów dla określonych typów zmiennych, ale programista ma możliwość sterowania (zmiany tego sposobu - oczywiście w rozsądny sposób). Rysunek przedstawia przyporządkowanie "by default" poszczególnych metod, poszczególnym rodzajom zmiennych:



Język przez adres Near przez adres Far przez wartość

BASIC wszystkie - -

C/C++ małe tablice duże tablice pozostale

FORTRAN wszystkie(medium model) wszystkie (large model) z atrybutami

PASCAL var, const vars,consts inne parametry





Kompilacja i linkowanie

Po odpowiednim napisaniu programu, z zastosowaniem odpowiednich konwencji, pora na kompilowanie i linkowanie poszczególnych modułów.



Kompilacja z odpowiednim modelem pamięci

W językach Pascal, Basic, Fortran nie ma specjalnych opcji wymaganych do kompilacji zbiorów źródłowych, będących częścią programu napisanego w językach mieszanych.

Ponieważ języki te używają tylko adresów kodu typu FAR należy wybrać jedną z dwu technik dla programu w języku C/C++ wywołującego podprogramy w jednym z tych języków:

- kompilować program w modelu: medium, huge lub large (używających również kodu adresu typu FAR)

- używanie słowa kluczowego __far do definicji funkcji publicznych języka C/C++.

Wybranie modelu pamięci w C,C++ lub Fortranie powoduje ustawienie rozmiaru wskaźnika danych "by default", chociaż mogą być one zmieniane słowami kluczowymi: __near, __far. Określa on również czy obiekt umieszczany jest w bieżącym segmencie danych. Jeśli nie, nie może być przesyłany przez adres typu __near.



Linkowanie z bibliotekami

W większości przypadków, można w prosty sposób łączyć moduły kompilowane różnymi językami. Aby zagwarantować, że wszystkie wymagane biblioteki linkowane będą w odpowiedniej kolejności, należy wykonać jedną z następujących czynności:

1. umieścić wszystkie biblioteki w tej samej kartotece co źródła

2. w zmiennej LIB określić katalogi zawierające wszystkie potrzebne biblioteki

3. pozwolić, aby linker promptował (prosił o określenie z ręki) biblioteki

W każdym powyższym przypadku, linker znajdzie biblioteki w kolejności jaka jest wymagana dla niego.

Link/NOD mod1 mod2,,,GRAFIX+LLIBCE+LLIBFOR

mod1,mod2 - dwa moduły napisane w językach mieszanych

GRAFIX- biblioteka użytkownika

LLIBCE - biblioteka C

LLIBFORE - biblioteka Fortranowska







Wywoływanie podprogramów języków wyższego poziomu

z poziomu C



Interfejsem do innych języków programowania w języku C jest użycie słów kluczowych __fortran/__pascal. Ich użycie powoduje, że podprogramy będą wywoływane używając Fortran/Pascal-owych konwencji nazewnictwa i wywołania. Konwencje te działają również dla Basic'a.

Aby poprawnie zrealizować wywołanie mieszane należy wykonać następujące działania:

1. napisać prototypy każdej wywoływanej mieszanej procedury. Prototyp powinien zawierać deklaracje extern, chociaż nie jest to wymogiem. Zamiast użycia w/w słów kluczowych, można stosować opcję /Gc. Powoduje ona, że wszystkie funkcje używają fortranowo/pascalowej konwencji z wyjątkiem tych które stosują słowo kluczowe __cdecl .

2. Przesłać zmienne lub adresy zmiennych, w sposób odpowiadający danej konwencji.

3. wykonać wywołanie funkcji w programie tak jak gdyby była to funkcja C

4. kompilować moduły C w medium huge lub large model, lub użyć __far w prototypie funkcji. Zapewni to wykonanie wywołania typu far.



Użycie słów kluczowych __pascal lub __fortran

Dwie zasady kierują użyciem tych słów:

1. modyfikują identyfikatory znajdujące się bezpośrednio po ich prawej stronie

2. razem z nimi mogą być użyte słowa __near, __far. Sekwencje:

__fortran__far

__far__fortran

sa ekwiwalentne

Słowo kluczowe:

__pascal - deklaruje podprogram Pascal-owy

__fortran - deklaruje podprogram Fortranowski

obie - deklarują podprogram BASIC-owski



Użycie tych słów daje ten sam efekt. Użycie jednego lub drugiego nie powoduje żadnych różnic, z wyjątkiem wewnętrznej dokumentacji programu.

Przykłady:

short __pascal func(short sarg1,short sarg2);

deklaracja funkcji func Basic-owa, Pascal-owa lub Fortran-owską pobierającą 2 argumenty short i zwracającą wartość short.



void (__fortran *func)(long larg);

deklaracja funkcji func Basic-owa, Pascal-owa lub Fortran-owską pobierającej zmienną long i nie zwracającej żadnej wartości. Void odpowiednie jest do użycia dla podprogramu w BASIC, procedury w PASCAL lub subroutine w FORTRAN, które nie zwracają wartości.



short __near__pascal func(__near double *darg);

równoważne:

short __pascal__near func(__near double *darg);

deklaracja funkcji func Basic-owa, Pascal-owa lub Fortran-owską typu near pobierającą argument przez referencjeadres) i zwracającą wartość short.



Przy wywoływaniu podprogramu w Basicu musimy używać w/w słów. Dla podprogramów Fortranowskich lub Pascalowych mamy wybór: albo adaptować C do konwencji F/P, albo adaptować Fortran lub Pascal do konwencji C. Ustawia się wówczas atrybut C w nagłówku definicji podprogramu. Następujące przykłady ilustrują sposób postępowania:

dla podprogramu Fortranowskiego:

SUBROUTINE FFROMC [C] (N)

INTEGER *2 N

dla podprogramu w Pascalu:

PROCEDURE Pfromc(n:integer) [C];

aby zaadaptować procedure C do konwencji P/F deklarujemy funkcje jako__pascal lu __fortran np.:

void __pascal CfromP(int n);









Wywołanie BASIC z poziomu C

Żaden podprogram napisany w Basic'u nie zostanie wykonany, jeśli program główny nie będzie napisany również w tym języku . Jest to spowodowane, wymaganiami co do środowiska, które musi być inicjowane w sposób unikalny dla tego języka. Żaden inny język nie wymaga takiej szczególnej inicjalizacji.

Jednakże, program może startować z poziomu Basic, wywoływać funkcję C wykonującą większość programu i wtedy wywołać podprogram w Basicu. Rysunek poniżej ilustruje jak to zrobić:







Przy wywoływaniu Basic z poziomu C należy postępować zgodnie z następującymi zasadami:

1. Napisać moduł główny w języku BASIC. Potrzebna jest instrukcja DECLARE określająca interfejs z C

2. W module C napisać prototyp dla podprogramu Basic i dołączyć informacje o typie parametrów. Użyć słów kluczowych __pascal lub __fortran

3. Upewnić się, czy wszystkie dane przesyłane są jako wskaźniki near. Basic może przesyłać parametry na różne sposoby, ale nie może otrzymać ich w inny sposób niż wskaźnik near. Jeśli chcemy przesłać dane nie mieszczące się w bieżącym segmencie, należy je przekopiować do zmiennej w segmencie bieżącym

4. Skompilować moduł C w modelu medium lub large



Poniższy program demonstruje program Basicowski wywołujący funkcję C, która z kolei wywołuje funkcję Basicowska, zwracającą podwojoną liczbę przesłaną do niej. Drukuje te dwie liczby:



'BASIC program

'The main program is in BASIC becouse of BASIC's startup

'requirements. The BASIC main program calls the C function Cprog

'Cprog calls the BASIC subroutine Db1

'

DEFINT A-Z

DECLARE SUB Cprog CDECL()

CALL Cprog

END

'

FUNCTION Db1(N) STATIC

Db1 = N*2

END FUNCTION

'

SUB Printnum(A,B) STATIC

PRINT "The first number is";A

PRINT "The second number is";B

END SUB



/* C source; compile in medium or large model

The parameters are declared as near pointer becouse of Basic requirements*/



int __fortran db1(int __near *N);

void __fortran printnum(int __near *A, int __near *B);



void cprog()

{

int a=5,b=6;

printf("%D times 2 is %d
,a,db1(&a) );

printnum(&a,&b);

}



Konwencje nazewnictwa i wywołań określane są przez słowo kluczowe CDECL w deklaracji Basicowej i __fortran w deklaracji funkcji db1 i printnum w module C.



Wywołanie podprogramu Fortranowskiego z poziomu C



W języku Fortran egzystują dwa rodzaje podprogramów: subroutine oraz function. Function zwraca wartość , subroutine nie. Poniżej przedstawione zostaną dwa przykłady ilustrujące różnice w użyciu function i subroutine.



Wywołannie subroutine z poziomu C



/* C source file - calls FORTRAN subroutine

compile in medium or large model */



extern void __fortran maxparam(int __near *I, int __near *J);



/*Declared as void becouse there is no return value;

Fortran keword causes C to use FORTRAN/PASCAL

calling and naming convenctios

two integer parameters, passed by near adresse */



main()

{

int a=5, b=7;



printf("a = %d, b = %d", a,b);

maxparam(&a,&b);

printf(" a=%d, b=%d", a,b);

}





C FORTRAN source file, subroutine MAXPARAM

C

$NOTRUNCATE

SUBROUTINE MAXPARAM(I,J)

INTEGER*2 I [NEAR]

INTEGER*2 J [NEAR]

C

C I and J received by near adress becouse of NEAR attribute

C

IF (I.GT.J) THEN

J=I

ELSE

I=J

ENDIF

END

Procedura maxparam przypisuje większemu parametrowi wartość mniejszego.

W tym przykładzie C program adoptuje konwencje Fortranowskie przy pomocy użycia w prototypie funkcji słowa kluczowego __fortran.

Ponieważ z treści wynika, iż parametry mogą zmieniać swoją wartość musimy je przesłać przez adres(referencje). W tym przypadku wybrano typ near. W związku z tym w programie Fortranowskim należy je również zadeklarować jako NEAR.

Gdybyśmy kompilowali program fortranowski w modelu medium, a parametry w C zadeklarowane byłyby jako FAR podobną operacje należałoby wykonać w programie fortranowskim.



Wywołanie function z poziomu C

Poniższy przykład demonstruje wywołanie z poziomu C Fortranowskiej funkcji liczącej silnię:fact:



/* C source file - calls FORTRAN function

compile in medium or large memory model */



int __fortran fact(int N);



/* Fortran keyword causes C to use FORTRAN calling and naming convenction.

Integer parameter passed by value */



main()

{

int x=3,y=4;

printf("The factorial of x is %4d",fact(x) );

printf("The factorial of y is %4d",fact(y) );

printf("The factorial of x+y is %4d",fact(x+y) );

}



C FORTRAN source file - factorial function

C

C N is received by value, because of VALUE attribute

C NOTRUNCATE - no truncate identifier name to 6 characters

C

$NOTRUNCATE

INTEGER *2 FUNCTION FACT (N)

INTEGER*2 N[VALUE]

C

INTEGER *2 I

FACT = 1

DO 100 I=1,N

FACT=FACT*I

100 CONTINUE

RETURN

END

Ponieważ w przeciwieństwie do poprzedniego przykładu parametry nie ulegały zmianie zdecydowano przesłać je przez wartość (sposób default dla języka C). Wymagało to określenia atrybutu VALUE dla przesyłanych parametrów w definicji funkcji Fortranowskiej.



Wywoływanie podprogramów Pascalowskich z poziomu C

W pascalu mamy do czynienia z dwoma rodzajami podprogramów: procedurą i funkcją. Procedura nie zwraca wartości, funkcja zwraca.



Procedura Pascalowa wywoływana z poziomu C

Procedura Pascalowska maxparam jest odpowiednikiem takiej samej w języku Fortran:



/* C source file - calls Pascal procedure. Compile in medium or large memory model */



void __pascal maxparam(int __near *a, int __near*b);



/* Declare as void becouse there is no return value.The __pascval keyword causes C to use PASCAL calling and naming convenction. Two integer parameters passed by near adress */



main()

{

int a=5,b=7;



printf("a=%d, b=%d",a,b);

maxparam(&a,&b);

printf("a=%d,b=%d",a,b);

}



{ Pascal source code = maxparam procedure }



MODULE Psub;

PROCEDURE Maxparam(var a:integer;var:b:integer);

begin

if a>b then

b:=a

else

a:=b;

end;

end.



W powyższym przykładzie ponieważ parametry przesyłane były przez adress near można było użyć w procedurze słowa VAR. Dla adresu far konieczne byłoby użcie VARS. Konwewncja pascalowa określana jest przez słowo kluczowe __pascal



Wywołanie funkcji Pascalowskiej z poziomu C

Funkcja jest odpowiednikiem funkcji z Fortranu:



/* C source file - calls PASCAL function

compile in medium or large memory model */



int __pascal fact(int N);



/* Pascal keyword causes C to use PASCAL calling and naming convenction.

Integer parameter passed by value */



main()

{

int x=3,y=4;

printf("The factorial of x is %4d",fact(x));

printf("The factorial of y is %4d",fact(y));

printf("The factorial of x+y is %4d",fact(x+y));

}



{ Pascal source code - factorial function }



MODULE Pfun;

FUNCTION Fact (n:integer):integer;

begin

fact:=1;

while n>0 do

begin

fact :=fact*n;

n:=n-1;

end;

end;

end.



Dla języka C++ interfejs pomiędzy językiem C++ i innym językiem wyższego poziomu odbywa się poprzez odniesienie do C. Mimo, że język C jest podzbiorem języka C++, ze względu na różnice między sposobem pracy ze stosem w momencie wywoływania funkcji (kolejność porządkowania, kolejność składowania parametrów na stosie) należy używając na poziomie C++ funkcji napisanych w C, dołączyć interfejs: extern "C"

{

void prin; // odwołanie do funkcji w języku C

}



extern "C" { int __pascal fact(int n); } //deklaruje funkcję napisaną w konwencji Pascala







Owołanie C do języków asemblerowych



Najczęstszym sposobem pisania "wstawek" asemblerowych jest użycie tzw. inline asemblera. Można również tworzyć samodzielne moduły w dostępnych asemblerach zewnętrznych. Jednak asembler "inline" jest bardziej efektywny od samodzielnych asemblerów. Oto kilka zalet takiego podejścia:

1. kod asemblera inline włączony jest do kodu języka C. Kod napisany w asemblerach zewnętrznych musi być umieszczony w oddzielnych plikach.

2. krótkie wstawki asemblerowe mogą optymalizować program

3. nie wymagają też wykonywania wywołania funkcji tak jak by to było a asemblerach zewnętrznych . Są to po prostu linie kodu tyle tylko, że w asemblerze

Nie będziemy mówili o asemblerach zewnętrznych. Powiemy tylko parę słów o asemblerze "inline";

Zakres użycia tej techniki jest bardzo szeroki jednak najczęściej stosowany jest do:

- poprawiania szybkości programu

-zmniejsza potrzeb co do zajętości pamięci

-użycie w prosty sposób funkcji DOS i BIOS z instrukcja INT

Asembler inline umożliwia umieszczenie kodu asemblerowego bezpośrednio w kodzie C. Jest wbudowany w kompilator i nie wymaga zewnętrznych asemblerów

Kod asemblerowy poprzedzony musi zostać słowem kluczowym asm:

__asm

{

mov ah,2

mov dl,7

int 21h

}

kod ten równoważny jest zapisowi:

__asm mov ah,2

__asm mov dl,7

__asm int 21h

Jeśli słowo kluczowe asm używane jest przed każdą instrukcja wtedy mogą być one umieszczone w jednej lini:

__asm mov ah,2 __asm mov dl,7 __asm int 21h



Funkcja asemblera inline w kodzie C



#include

int power2(int num,int power);

void main(void)

{

printf("3 times 2 to the powerr of 5 is %d
",power2(3,5) );

}

int power2(int num,int power)

{

__asm

{

mov ax,num;

mov cx,power;

shl ax,cl;

}

/* return with result in ax */

}





Wywoływanie funkcji C w bloku asemblerowym

W bloku __asm możemy wywoływać funkcje biblioteczne języka C: wykonuje to instrukcja CALL:



#include

char format[]="%s %s";

char hello[] = "Hello";

char world[] = "world";



void main(void)

{

__asm

{

mov ax, offset world

push ax

mov ax, offset hello

push ax

mov ax, offset

push ax

call printf

}

}

funkcja printf zbiera swoje argumenty, które umieszczane są na stosie.

Powyższy kod emuluje zapis C:

printf(format,hello,world);

























Informacje dodatkowe



Domyślne przyjęcie konwencji nazewnictwa i wywołań



Język Konwencja wywołań Konwencja nazewnictwa Przesyłanie parametrów

BASIC Fortran/Pascal Case insesitive Near adress

C C Case sensitive Value(scalar value)

address(array)

C++ Fortran/Pascal Case sensitive Value(scalar value)

address(array)

FORTRAN Fortran/Pascal Case insesitive address

PASCAL Fortran/Pascal Case insesitive Value



Odpowiedniki typów danych



BASIC C/C++ FORTRAN Pascal

x% short INTEGER *2 INTEGER2

INTEGER int - INTEGER

- unsigned short - WORD

- unsigned - -

x& long INTEGER*4 INTEGER4

LONG - INTEGER -

- unsigned long - -

x! float REAL *4 REAL4

x(default) - REAL REAL

x# double REAL*8 REAL8

DOUBLE - DOUBLE PRECISION -

- long double - -

- unsigned char CHARACTER *1 CHAR

SINGLE - - -



Czy tekst był przydatny? Tak Nie
Przeczytaj podobne teksty

Czas czytania: 26 minut