🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.c
Article #267822

Re: Ciemna strona C++

#267822
From: Sektor van Skijlen
Date: Tue, 04 Dec 2007 00:37
227 lines
13889 bytes
Dnia Mon, 26 Nov 2007 15:40:23 +0100, Marcin ?Qrczak? Kowalczyk skrobie:
> Dnia 26-11-2007, Pn o godzinie 12:58 +0000, Sektor van Skijlen pisze:

> > > - rozkład pól w strukturach (nazwy pól, typy, ich kolejność)
> > >   i metod w klasach (w przypadku C++)
> > 
> > Nie. No co ty. Jak obsłużysz np. sytuację, gdy pole jest takiego typu, które
> > ma jakiś własny operator przypisania i robi różne dziwactwa? Co ci w takim
> > przypadku po znajomości delty pola?

> Napisałem też: typy. Nie mówię, że offset wystarcza, tylko że jest
> konieczny, żeby dostać się do pól. Jeśli pola są publiczne, to dostęp
> do nich może być kluczową częścią interfejsu obiektu.

Do jasnej cholery, ja się natłumaczę, a ty dalej swoje.

> Mowa była o tych danych potrzebnych do użycia biblioteki, których nie ma
> ani w *.so, ani nie są normalnie znane komuś, kto zna źródłowy interfejs
> biblioteki (w przeciwieństwie do binarnego). A mowa ta była po to, żeby
> pokazać, że do dynamicznego użycia dowolnej biblioteki C++ nie wystarczy
> jakiś wzbogacony dlopen, tylko trzeba wnioskować na podstawie deklaracyj
> w pliku nagłówkowym.

Qrczak, zrozum wreszcie i przestań się kręcić w kółko: pojęcia takie, jak
offset pola, czy wielu innych rzeczy, które są dostępne w pliku nagłówkowym
DLA C++, a nie ma żadnej informacji nit. w bibliotece dynamicznej, to są
wszystko sprawy, które mają sens w C++ i TYLKO w C++.

Jeśli te wszystkie podobne kwestie miałyby być odwzorowane w jakiś sposób dla
innego języka programowania - to ewentualnie można dorobić dodatkowy
interfejs, do którego można się dobrać z poziomu języka C (w przypadku
większości współczesnych platform natywnych jest to tożsame ze stwierdzeniem
"z poziomu biblioteki dynamicznej"), może ewentualnie dałoby się zrobić jakiś
specjalizowany mostek między C++ a jakimś określonym językiem (tak jak to robi
boost::python).

Jeśli więc bezpośredni dostęp do pól jest rzeczą nieodzowną w interfejsie
biblioteki, to znaczy, że można jej używać tylko z poziomu takiego języka,
który będzie umiał sobie to odpowiednio przełożyć; jeśli mówimy o szablonach,
to znaczy, że jest to interfejs przeznaczony dla C++ i tylko dla C++. Jeśli
bez dostępu do szablonu nie da się używać tej biblioteki - a tak jest w
przypadku np. boost::bind - to znaczy, że nie da się tej biblioteki
interfejsować dla żadnego języka innego, niż C++. I nie ma w tym nic złego,
ani dziwnego.

Zastanów się najpierw, jak to możliwe, że możesz używać w bibliotece stdio
struktury FILE, mimo że najczęściej nie masz jej definicji nawet w pliku
nagłówkowym!

> > Przypominam zresztą na marginesie, że w Javie też nie masz dostępu do
> > informacji o delcie pola (tzn. inaczej - informacja ta jest teoretycznie
> > dostępna, wraz z nazwami pól i deskryptorami ich typów, tyle że z tej
> > informacji nie jesteś w stanie zrobić żadnego użytku).

> Ale w Javie nie ma po co, bo mając dowolny obiekt i nazwę jego pola
> w stringu można się dostać do tego pola.

Zgadza się - i być może miałoby sens używanie tego samego triku w przypadku
C++ (w sensie, mapa nazw pól z ich deltami i deskryptorami typów). Jeśli ktoś
by tego potrzebował.

W Javie się da, bo w Javie da się utworzyć obiekt, odwołać do jego pola i
wywołać jego metodę, wczytując wszystkie nazwy tych symboli z zewnętrznego
pliku.

> > Jeśli już podałeś Javę, jako przykład, to przypominam ci, że z pliku *.class
> > można otrzymać z powrotem DOKŁADNIE IDENTYCZNE ŹRÓDŁO danej klasy.

> Trzeba rozróżnić dwie sprawy:

> 1. Uzyskanie informacji o sobie samym przez działający program.

> 2. Uzyskanie informacji o programie na podstawie jego wersji źródłowej
>    bądź skompilowanej postaci pośredniej tego programu. Program nie musi
>    być w danej chwili uruchomiony.

No, na razie mówimy tylko o przypadku #2.

> Obie sprawy mogą pomóc uzyskać wiązanie do innego języka.

Tak, ale zwykle jedno się łączy z drugim. W C++ nie możesz się dobrać po
nazwie do pola, ale nie dlatego, że nie ma mapowania do tej nazwy w
wykonującym się programie, ale nie ma również w skompilowanym programie.

> Ja się w tym
> wątku skupiałem na pierwszej; ona może służyć do generowania wiązania
> niejako w locie, bez kompilacji czegokolwiek, czasem nawet bez
> konieczności statycznego przewidywania, co może być udostępniane.

Czekaj, czekaj.

Jak ty sobie to przepraszam wyobrażasz? Przecież jeśli mam program w,
powiedzmy, Jythonie, który usiłuje stworzyć obiekt typu
com.lego.technic.BasicBlock, to musi to jego żądanie zostać zrealizowane
poprzez jakiś mechanizm, który mu to umożliwia, w tym przypadku sam JVM, ale
to nie zmienia faktu, że JVM nie spełni tego żądania na podstawie danych
wziętych z powietrza, tylko po prostu wczyta na żywca plik *.class - ten sam
dokładnie plik, który mogę wczytać moim własnym super-wczytywaczem i na
podstawie dostępnych tam informacji wykonać żądane operacje.

Skąd byś te informacje wziął, gdyby nie były zawarte w pliku *.class?

> To jest przydatne w przypadku dostawania się do bibliotek z poziomu
> języków interpretowanych, np. z Pythona (w formie Jythona).

> Z kolei druga jest przydatna, kiedy chcemy dostać się do bibliotek
> jakiegoś języka z poziomu języka statycznie typowanego, który musi
> mieć widoczne deklaracje zawczasu.

> Uwaga: w tym miejscu mówię o językach, z których dostajemy się do
> biblioteki, a nie o implementujących bibliotekę.

To wszystko nie ma większego znaczenia - wbrew temu, co ci się wydaje.

Jeśli biblioteka ma być używana z poziomu języka X, a jest zaimplementowana w
języku Y, to musi mieć interfejs dla języka X stworzony z uwzględnieniem
wszystkich reguł sztuki pisania w języku X i udostępniający całą
funkcjonalność (lub minimum wszystkich elementów, które wystarczy do
udostępnienia całej funkcjonalności) poprzez ten interfejs.

Jest wiele sposobów na to, jak to zrobić i wiele zależy tutaj od
charakterystyki języka X oraz od platformy docelowej.

Jeśli mówimy o platformie natywnej współczesnych systemów operacyjnych, to
wszystko musi być udostępnione jako funkcja (wołana przez wskaźnik) albo jako
obiekt. Jeśli język X daje możliwość dobierania się do wskaźnika na funkcję
lub obiekt udostępniane przez bibliotekę dynamiczną, to platforma natywna może
służyć tu jako pośrednik. To znaczy, zestaw symboli biblioteki
zaimplementowanej w języku Y musi pokrywać minimum funkcjonalne biblioteki, a
na tej podstawie można zrobić interfejs do niej dla języka X.

Trochę inaczej - acz łatwiej - może się mieć sprawa w przypadku innych
platform, takich jak JVM. Tam masz dostęp do większej ilości informacji. To
jednak jedynie oznacza, że masz odrobinę większe prawdopodobieństwo, że
minimum funkcjonalne zostanie pokryte przez symbole eksportowane z biblioteki.
Nadal jednak nie masz dostępu do wszystkiego - nie wiem, jak tam Jython radzi
sobie z generykami w Javie, ale o ile ja się orientuję, nie są one
odwzorowywane odpowiednio w plikach wynikowych (tzn. ich działalność jest
zacierana w kodzie, który ich używa, przez zastąpieniu typu parametru typem
Object lub jawnym przodkiem typu parametru).

Jeszcze inna sprawa jest jeśli możesz stworzyć mostek bezpośrednio pomiędzy
dwoma językami.

> Przy czym niektóre języki statycznie typowane mogą też skorzystać
> z pierwszej metody. Na przykład Java niby jest statycznie typowana,
> ale używalny dla niej (choć niewygodny) byłby interfejs opierający się
> na amorficznych obiektach typu Object z funkcjami określanymi przez
> stringi i z rzutowaniem w celu wydobycia wartości odpowiedniego typu.
> Nawet C++ może tak próbować, co pokazuje zdaje się Boost.Python.

Jak więc widzisz, nie ma żadnej większej różnicy pomiędzy używaniem biblioteki
tylko w czasie kompilacji i rozwiązywaniem dostępu dopiero podczas
wykonywania. To w największym stopniu zależy od języka, w którym napisano
program korzystający z biblioteki.

> > > - definicje makr
> > 
> > I jak przepraszam przetłumaczysz treść takiego makra na, powiedzmy, Pythona?

> Dla każdego makra interfejs w Pythonie trzeba projektować indywidualnie.

I to samo dotyczy każdego innego języka.

Co więcej, w niektórych mogłoby to nie mieć sensu, lub może mieć on znacznie
sensowniejsze na to sposoby.

> Jeśli jednak istotna funkcjonalność biblioteki jest dostępna wyłącznie
> przez makra, to jakoś trzeba sobie z nimi radzić.

Najczęściej poprzez napisanie ich niemalże od nowa. Pół biedy jeszcze, jeśli
one upraszczają zakręcony interfejs z języka kompilowanego. Gorzej jeśli
teoretycznie dałoby się to samo zakodować w funkcji.

Jak by nie było: jeśli ktoś nie przewidział używania tego z innego poziomu,
niż język, w którym jest zaimplementowana, to nie ma lekko. Przerobienie
bazowego interfejsu, a nawet implementacji specjalnie do tego celu, aby to
było możliwe, jest niekiedy nieodzowne.

> Przykład makr (innych niż stałe całkowite), które są jedyną oficjalną
> drogą uzyskania istotnej funkcjonalności biblioteki: WIFEXITED(status),
> WEXITSTATUS(status) itd. przy funkcjach wait / waitpid.

> Jak sobie z nimi poradzić: np. obudować w funkcje. Przy czym niektórzy
> bardziej leniwi autorzy wiązania dla danej biblioteki albo autorzy
> używający bardziej prymitywnych FFI zamiast tego oglądają treść makra
> na swoim systemie i ręcznie duplikują jego funkcjonalność w innym
> języku. W przypadku makr z rodziny WIFEXITED chyba nawet istnieje
> ogólnie przyjęta uniksowa konwencja, więc takie postępowanie nie jest
> całkiem pozbawione sensu, ale i tak go nie lubię.

Ale przyczyna "nielubienia" tego podejścia nie polega na tym, że się
interfejsuje makro poprzez duplikację jego kodu, tylko na tym, że
używa się makra w interfejsie.

Moim zdaniem makro powinno, w miarę na ile to możliwe, przekierowywać
wywołanie do odpowiedniej funkcji. I to tak, żeby jego definicja była prosta i
jawna - żeby można było w sposób całkowicie legalny i bezpieczny je
duplikować.

Taka zasada zwykle obowiązuje makra w przypadku interfejsów w C++. Tam zresztą
z reguły nie należą one do wymaganego minimum interfejsu i stanowią jedynie
ułatwienia dla użytkownika.

> Kogut w obecnej formie nie ma FFI niezależnego od implementacji Koguta.
> To jest niestety skomplikowana sprawa. Miałem nadzieję, że praktyka
> używania tego FFI do C, co mam, spowoduje wyklarowanie się, co będzie do
> takiego przenośnego FFI potrzebne, ale okazuje się, że im dalej w las,
> tym więcej drzew. Ponieważ zależy mi na ładnym interfejsie do bibliotek,
> które obudowuję, na eliminowaniu zachowania niezdefiniowanego i na
> przenośności względem wersji biblioteki, oraz ze względu na duże różnice
> między obydwoma językami, różne biblioteki wymagają bardzo wymyślnych
> akrobacji. Do tego to FFI, które mam, mimo moich starań jest dość
> pracochłonne w użyciu. Za to efekty są sprawne; ponieważ kompiluję
> Koguta do C, to komunikacja z daną biblioteką jest "ciasna" i może być
> efektywna.

Na pewno tak, ale nie wiem, czy nie oznacza to również, że być może biblioteki
w C++ byłoby nawet łatwiej interfejsować - jeśli ktoś by je z tym
uwzględnieniem pisał.


-- 
//  _    ___         Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl>
\\ L_ |/ `|  /^\ ,()                         <ethouris(O)gmail.com>
// \_ |\  \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx
"Java is answer for a question that has never been stated"
Technical Details
Message-ID: <fj27gl$cht$1@kujawiak.man.lodz.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mail
References: <fghgeo$spf$1@nemesis.news.tpi.pl> <fghsb4$kpq$1@news.dialog.net.pl> <fgo4c7$mtu$1@news.vectranet.pl> <20071106073039.433f4934@Vorago> <fgqn9m$74j$2@news.vectranet.pl> <618565031.20071107113041@pkierski.net> <fgt6sh$jov$1@news.vectranet.pl> <fgtb6j$nur$1@news.vectranet.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <fi458p$fmv$1@bozon2.softax.pl> <fi9ckc$2u5$1@kujawiak.man.lodz.pl> <1195918508.27382.40.camel@qrnik> <fi9hmg$dct$1@news.vectranet.pl> <1195922067.12235.1.camel@qrnik> <fia74t$28b$1@news.vectranet.pl> <1195947820.12235.76.camel@qrnik> <fiefu7$faq$1@kujawiak.man.lodz.pl> <1196088022.2991.95.camel@qrnik>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mail
From: Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
Newsgroups: pl.comp.lang.c
Subject: Re: Ciemna strona C++
Date: Tue, 4 Dec 2007 00:37:41 +0000 (UTC)
Organization: LODMAN - Metropolitan Area Network in LODZ, Poland
Lines: 227
Sender: Michal Malecki <sektor@student.kis.p.lodz.pl>
Message-ID: <fj27gl$cht$1@kujawiak.man.lodz.pl>
References: <fghgeo$spf$1@nemesis.news.tpi.pl> <fghsb4$kpq$1@news.dialog.net.pl> <fgo4c7$mtu$1@news.vectranet.pl> <20071106073039.433f4934@Vorago> <fgqn9m$74j$2@news.vectranet.pl> <618565031.20071107113041@pkierski.net> <fgt6sh$jov$1@news.vectranet.pl> <fgtb6j$nur$1@news.vectranet.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <fi458p$fmv$1@bozon2.softax.pl> <fi9ckc$2u5$1@kujawiak.man.lodz.pl> <1195918508.27382.40.camel@qrnik> <fi9hmg$dct$1@news.vectranet.pl> <1195922067.12235.1.camel@qrnik> <fia74t$28b$1@news.vectranet.pl> <1195947820.12235.76.camel@qrnik> <fiefu7$faq$1@kujawiak.man.lodz.pl> <1196088022.2991.95.camel@qrnik>
NNTP-Posting-Host: student.kis.p.lodz.pl
Mime-Version: 1.0
X-Trace: kujawiak.man.lodz.pl 1196728661 12861 212.191.89.21 (4 Dec 2007 00:37:41 GMT)
X-Complaints-To: abuse@man.lodz.pl
NNTP-Posting-Date: Tue, 4 Dec 2007 00:37:41 +0000 (UTC)
User-Agent: tin/1.8.3-20070201 ("Scotasay") (UNIX) (FreeBSD/6.2-RELEASE-p3 (sparc64))
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit