Article View: pl.comp.lang.c
Article #267822Re: Ciemna strona C++
From: Sektor van Skijlen
Date: Tue, 04 Dec 2007 00:37
Date: Tue, 04 Dec 2007 00:37
227 lines
13889 bytes
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-mailReferences:
<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