{"id":30980,"date":"2025-05-07T05:00:00","date_gmt":"2025-05-07T03:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=30980"},"modified":"2025-05-07T13:09:12","modified_gmt":"2025-05-07T11:09:12","slug":"jak-sie-dogadac-z-innymi-jezykami-wywolywanie-obcych-funkcji-w-kodzie-c-c","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/jak-sie-dogadac-z-innymi-jezykami-wywolywanie-obcych-funkcji-w-kodzie-c-c\/","title":{"rendered":"Jak si\u0119 dogada\u0107 z innymi j\u0119zykami? Wywo\u0142ywanie obcych funkcji w kodzie C\/C++"},"content":{"rendered":"\n<p>Wiele programist\u00f3w, szczeg\u00f3lnie wywodz\u0105cych si\u0119 ze \u015brodowiska embedded, specjalizuje si\u0119 w j\u0119zykach C\/C++. W tym artykule zach\u0119cam do wyj\u015bcia poza utarty schemat i spojrzenia na mo\u017cliwo\u015bci rozszerzenia w\u0142asnej aplikacji o funkcjonalno\u015b\u0107 napisan\u0105 w innym j\u0119zyku wy\u017cszego poziomu. W tym przypadku mam na my\u015bli j\u0119zyki Java\/Python, poniewa\u017c w mniejszym stopniu zale\u017c\u0105 od architektury, na kt\u00f3rej si\u0119 wykonuj\u0105.<\/p>\n\n\n\n<p>Wi\u0119kszo\u015b\u0107 opisywanych przypadk\u00f3w skupia si\u0119 na wywo\u0142ywaniu kodu ni\u017cszego poziomu. W przypadku Javy jest <em>to Java Native Interface<\/em>, a dla Pythona s\u0105 to <em>Extensions Modules<\/em>. <strong>Brakuje natomiast opis\u00f3w<\/strong> tego, jak zrobi\u0107 rzecz odwrotn\u0105, czyli <strong>jak stworzy\u0107 \u015brodowisko dla dzia\u0142ania j\u0119zyka wy\u017cszego poziomu<\/strong>. Zamierzam pokaza\u0107, jak komunikowa\u0107 si\u0119 z tym innym \u015bwiatem w naszym programie i <strong>zobrazuj\u0119 to na konkretnych przyk\u0142adach dla tych dw\u00f3ch j\u0119zyk\u00f3w.<\/strong><\/p>\n\n\n\n<p>Zapraszam do lektury!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Python<\/strong><\/h2>\n\n\n\n<p>Aby program w j\u0119zyku C++ si\u0119 skompilowa\u0142, nale\u017cy zadba\u0107 o dost\u0119p do bibliotek z pakietu Python3. W CMakeLists.txt zajmuj\u0105 si\u0119 tym nast\u0119puj\u0105ce linie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfind_package(Python3 REQUIRED COMPONENTS Interpreter Development)\n#\n# ...definicja projektu o nazwie w ${PRJ_NAME}...\n#\ntarget_include_directories(${PRJ_NAME} PRIVATE ${Python3_INCLUDE_DIRS})\ntarget_link_libraries(${PRJ_NAME} PUBLIC ${Python3_LIBRARIES})\n<\/pre><\/div>\n\n\n<p>Oczywi\u015bcie wcze\u015bniej nale\u017cy mie\u0107 zainstalowane odpowiednie biblioteki w systemie. W Ubuntu jest to pakiet <strong>python3-dev<\/strong>.<\/p>\n\n\n\n<p>Przyk\u0142adowy kod w j\u0119zyku Python, kt\u00f3ry b\u0119dzie uruchamiany w naszej aplikacji, jest pokazany poni\u017cej. B\u0119dzie zapisany w pliku my_module.py. Zawiera prost\u0105 funkcj\u0119 statyczn\u0105 oraz klas\u0119 z metod\u0105, kt\u00f3ra zwraca ci\u0105g znak\u00f3w. Klasa przechowuje w polu \u2018name\u2019 warto\u015b\u0107, kt\u00f3r\u0105 ustawia si\u0119 w konstruktorze. Ponadto klasa zawiera metod\u0119 \u2018greet\u2019, kt\u00f3ra wypisuje na ekran komunikat z nadanym imieniem.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef hello():\n    print(&quot;&#x5B;Python]: Hello!&quot;)\n\ndef print_stuff(a,b):\n    print(&quot;&#x5B;Python]: Hello world! Your numbers are:&quot;, a, &quot;and&quot;, b)\n    return 5\n\nclass MyClass:\n    def __init__(self, name):\n        self.name = name\n    \n    def greet(self):\n        return f&quot;Hello, my name is {self.name}!&quot; \n<\/pre><\/div>\n\n\n<p>Minimalny program, kt\u00f3ry przygotowuje \u015brodowisko i za\u0142aduje nasz modu\u0142, jest przedstawiony poni\u017cej. Jest napisany w C++, ale kluczowe funkcje by\u0142yby takie same w programie w C. Do samej inicjalizacji wystarczy jedynie wywo\u0142anie Py_Initialize(), natomiast pozosta\u0142e linie zapewniaj\u0105 poprawne znalezienie naszego programu pliku .py. Za\u0142o\u017cenie jest takie, \u017ce znajduje si\u0119 on w tym samym katalogu, co plik \u017ar\u00f3d\u0142owy programu kompilowanego.<\/p>\n\n\n\n<p>W typowej konfiguracji cmake plik wykonywalny po skompilowaniu b\u0119dzie znajdowa\u0142 si\u0119 w innym miejscu i nie by\u0142by w stanie znale\u017a\u0107 tego modu\u0142u. W tym celu ustawiona zostaje zmienna \u015brodowiskowa PYTHONPATH na podstawie makra __FILE__. Alternatywnie, mo\u017cna t\u0105 zmienn\u0105 ustawi\u0107 r\u0119cznie w konsoli przed uruchomieniem programu i efekt b\u0119dzie ten sam. <strong>Przedstawione podej\u015bcie jest o tyle lepsze, \u017ce nie wymaga od u\u017cytkownika dodatkowych czynno\u015bci.<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#include &lt;filesystem&gt;\n#define PY_SSIZE_T_CLEAN\n#include &lt;Python.h&gt;\n\nint main(int argc, char** argv)\n{\n    using std::filesystem::path;\n    using std::filesystem::weakly_canonical;\n    const auto src_dir {weakly_canonical(path(__FILE__)).parent_path()};\n    static constexpr int OverwriteVariable = 1;\n    setenv(&quot;PYTHONPATH&quot;, src_dir.c_str(), OverwriteVariable);\n    \n    Py_Initialize();\n\n    PyObject* my_module = PyImport_ImportModule(&quot;my_module&quot;);\n    if(my_module == nullptr){\n        PyErr_Print();\n        return -1;\n    }\n\n    Py_DECREF(my_module);\n\n    Py_Finalize();\n    return 0;\n}\n<\/pre><\/div>\n\n\n<p>Nast\u0119pnie mo\u017cna ju\u017c za\u0142adowa\u0107 nasz modu\u0142 za pomoc\u0105 PyImport_ImportModule(). <strong>Niech nie umknie uwadze<\/strong> to, \u017ce nazwa modu\u0142u jest przekazywana bez rozszerzenia *.py. Je\u017celi je dodamy, to funkcja zwr\u00f3ci NULL, a PyERR_Print() wypisze szczeg\u00f3\u0142y problemu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"574\" height=\"32\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz1-1.png\" alt=\"kod\" class=\"wp-image-30981\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz1-1.png 574w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz1-1-300x17.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz1-1-555x32.png 555w\" sizes=\"(max-width: 574px) 100vw, 574px\" \/><\/figure>\n\n\n\n<p>Modu\u0142 jest zwracany jako wska\u017anik na typ PyObject. Jest to uniwersalny typ, odzwierciedlaj\u0105cy dynamiczny spos\u00f3b typowania w Pythonie. Wszystkie obiekty s\u0105 reprezentowane tak samo i dopiero w momencie wykonania jakiej\u015b operacji jest sprawdzane, czy dana instancja pasuje do kontekstu.<\/p>\n\n\n\n<p>Jedn\u0105 z ostatnich operacji wykonanych w programie jest Py_DECREF() na obiekcie modu\u0142u. Jest to zwi\u0105zane z zarz\u0105dzaniem czasem \u017cycia projektu. W Pythonie obiekty s\u0105 automatycznie niszczone, kiedy nie s\u0105 ju\u017c potrzebne. S\u0142u\u017cy do tego licznik referencji obiektu. W przypadku niskopoziomowego u\u017cywania obiekt\u00f3w, nale\u017cy nim zarz\u0105dza\u0107 r\u0119cznie, aby zapobiec wyciekom pami\u0119ci. Po wywo\u0142aniu tej funkcji licznik jest zmniejszany i je\u017celi osi\u0105gnie 0, to obiekt zostanie zniszczony. Na samym ko\u0144cu powinno si\u0119 wywo\u0142a\u0107 Py_Finalize(), kt\u00f3re zwalnia zasoby \u015brodowiska uruchomieniowego Python.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Mechanizm automatycznej deaolokacji zasob\u00f3w<\/strong><\/h3>\n\n\n\n<p><strong>Zanim przejd\u0119 do uruchamiania kolejnych przyk\u0142ad\u00f3w, wprowadz\u0119 mechanizm automatycznej dealokacji zasob\u00f3w<\/strong>. J\u0119zyk C++ umo\u017cliwia to dzi\u0119ki technice RAII, kt\u00f3ra zwalnia programist\u0119 z r\u0119cznego uruchamiania funkcji zwalniaj\u0105cej zasoby. Mo\u017cna to uzyska\u0107 poprzez specjalizacj\u0119 klasy std::unique_ptr z odpowiednim typem <em>Deleter<\/em>. Dzi\u0119ki temu funkcja Py_DECREF() zostanie wywo\u0142ana na ka\u017cdym chronionym obiekcie, np. kiedy wyj\u015bcie z funkcji nast\u0105pi wcze\u015bniej na skutek wyst\u0105pienia b\u0142\u0119du.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#include &lt;memory&gt;\nstatic auto pyobject_deleter = &#x5B;](PyObject* pObject)\n{\n    if(pObject){\n        Py_DECREF(pObject);\n    }\n};\nusing PyObjectUniquePtr = std::unique_ptr&lt;PyObject, decltype(pyobject_deleter)&gt;;\n<\/pre><\/div>\n\n\n<p>Uzbrojeni w nowe narz\u0119dzie, mo\u017cemy przej\u015b\u0107 do wywo\u0142ania funkcji statycznej, czyli niepowi\u0105zanej z \u017cadn\u0105 instancj\u0105 klasy. Dla zwi\u0119z\u0142o\u015bci przyk\u0142adu, sprawdzanie poprawno\u015bci za\u0142adowania modu\u0142u zosta\u0142o pomini\u0119te. Funkcja jest po prostu kolejnym obiektem, kt\u00f3ry jest dost\u0119pny jako atrybut modu\u0142u. Do wywo\u0142ania dowolnego obiektu u\u017cywa si\u0119 jednej funkcji z rodziny PyObject_Call*(). Je\u017celi nie zamierzamy przekazywa\u0107 \u017cadnych parametr\u00f3w, to optymalnym wyborem jest PyObject_CallNoArgs().<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nPyObjectUniquePtr my_module {PyImport_ImportModule(&quot;my_module&quot;)};\n    PyObjectUniquePtr hello {PyObject_GetAttrString(my_module.get(), &quot;hello&quot;)};\n    PyObject_CallNoArgs(hello. Get());\n<\/pre><\/div>\n\n\n<p>Po uruchomieniu programu w konsoli pojawi si\u0119 komunikat wygenerowany przez kod Pythona:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"358\" height=\"31\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz2-1.png\" alt=\"kod\" class=\"wp-image-30983\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz2-1.png 358w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz2-1-300x26.png 300w\" sizes=\"(max-width: 358px) 100vw, 358px\" \/><\/figure>\n\n\n\n<p>A co, je\u017celi chcemy przekaza\u0107 jak\u0105\u015b warto\u015b\u0107? Najpierw nale\u017cy j\u0105 przekonwertowa\u0107 na instancj\u0119 klasy PyObject. Biblioteka Pythona dostarcza ca\u0142y zestaw takich funkcji. Ponadto istnieje wi\u0119cej ni\u017c jedna metoda wywo\u0142ania funkcji z kilkoma parametrami. Jedn\u0105 z nich jest wariadyczna funkcja PyObject_CallFunctionObjArgs(), gdzie ostatnim parametrem zamykaj\u0105cym list\u0119 musi by\u0107 NULL.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nPyObjectUniquePtr print_stuff {PyObject_GetAttrString(my_module.get(), &quot;print_stuff&quot;)};\n    PyObjectUniquePtr arg1 {PyLong_FromLong(99)};\n    PyObjectUniquePtr arg2 {PyLong_FromLong(42)};\n    PyObjectUniquePtr ret_val{PyObject_CallFunctionObjArgs(print_stuff.get(), arg1.get(), arg2.get(), nullptr)};\n    fmt::print(&quot;Function returned {}\\n&quot;, PyLong_AsLong(ret_val.get()));\n<\/pre><\/div>\n\n\n<p>Wynik dzia\u0142ania kodu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"381\" height=\"122\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz3.png\" alt=\"kod\" class=\"wp-image-30985\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz3.png 381w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz3-300x96.png 300w\" sizes=\"(max-width: 381px) 100vw, 381px\" \/><\/figure>\n\n\n\n<p>Alternatywnie, parametry mo\u017cna przekaza\u0107 jako Pythonow\u0105 tupl\u0119, kt\u00f3r\u0105 nale\u017cy wcze\u015bniej stworzy\u0107. Nast\u0119pnie nale\u017cy wywo\u0142a\u0107 funkcje PyObject_CallObject(). Do przetworzenia obiekt\u00f3w Pythona na zmienne typu integer s\u0142u\u017cy funkcja PyLong_AsLong().<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nPyObjectUniquePtr args_tuple{PyTuple_Pack(2, PyLong_FromLong(99), PyLong_FromLong(42))};\n    PyObjectUniquePtr ret_val {PyObject_CallObject(print_stuff.get(), args_tuple.get())};\n    fmt::print(&quot;Function returned {}\\n&quot;, PyLong_AsLong(ret_val.get()));\n<\/pre><\/div>\n\n\n<p>Wynik dzia\u0142ania kodu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"359\" height=\"69\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz4.png\" alt=\"kod\" class=\"wp-image-30987\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz4.png 359w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz4-300x58.png 300w\" sizes=\"(max-width: 359px) 100vw, 359px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Operowanie na instancji obiektu<\/strong><\/h3>\n\n\n\n<p>Kolejnym poziomem zaawansowania jest operowanie na instancji obiektu. Klas\u0119 odnajduje si\u0119 tak samo jak zwyk\u0142\u0105 funkcj\u0119, poprzez znalezienie atrybutu w module. \u017beby stworzy\u0107 jej instancj\u0119, nale\u017cy wywo\u0142a\u0107 uprzednio znaleziony obiekt, co jest r\u00f3wnoznaczne z uruchomieniem konstruktora. W naszym przypadku klasa przyjmuje tekst, w tym przypadku \u201eBob\u201d. Nast\u0119pnie z instancji klasy zostaje pobrana metoda \u201egreet()\u201d. Po jej wywo\u0142aniu, ci\u0105g tekstowy zostaje wyci\u0105gni\u0119ty ze zwr\u00f3conego obiektu za pomoc\u0105 funkcji PyUnicode_AsUTF8().<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nPyObjectUniquePtr class_ref{PyObject_GetAttrString(my_module.get(), &quot;MyClass&quot;)};\n    PyObjectUniquePtr args {PyTuple_Pack(1, PyUnicode_FromString(&quot;Bob&quot;))};\n    PyObjectUniquePtr object {PyObject_CallObject(class_ref.get(), args.get())};\n    PyObjectUniquePtr method {PyObject_GetAttrString(object.get(), &quot;greet&quot;)};\n    PyObjectUniquePtr result {PyObject_CallNoArgs(method.get())};\n    fmt::print(&quot;Function returned: &#039;{}&#039;\\n&quot;, PyUnicode_AsUTF8(result.get()));\n<\/pre><\/div>\n\n\n<p>Wynik dzia\u0142ania kodu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"323\" height=\"170\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz5.png\" alt=\"kod\" class=\"wp-image-30989\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz5.png 323w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz5-300x158.png 300w\" sizes=\"(max-width: 323px) 100vw, 323px\" \/><\/figure>\n\n\n\n<p>Powy\u017csze przyk\u0142ady pokazuj\u0105, <strong>jak \u0142atwe jest przekazywanie danych do i z funkcji napisanych w j\u0119zyku Python<\/strong>. <strong>Inn\u0105 mo\u017cliwo\u015bci\u0105 integracji jest u\u017cycie biblioteki Boost.Python albo pybind<\/strong>. Zawieraj\u0105 one gotowe klasy kompatybilne z obiektami Pythona.<\/p>\n\n\n\n<p>A jak wygl\u0105da sytuacja z Jav\u0105?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Java<\/strong><\/h2>\n\n\n\n<p>Projekt CMake b\u0119dzie wygl\u0105da\u0142 analogicznie \u2013 r\u00f3wnie\u017c trzeba doda\u0107 \u015bcie\u017cki z nag\u0142\u00f3wkami oraz zlinkowa\u0107 program z kilkoma bibliotekami z przestrzeni JNI. W systemie musz\u0105 by\u0107 zainstalowane pakiety <strong>openjdk-8-jre<\/strong> oraz <strong>openjdk-8-jdk<\/strong>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\nfind_package(JNI REQUIRED)\n#\n# ...definicja projektu o nazwie w ${PRJ_NAME}...\n#\ntarget_include_directories(${PRJ_NAME} PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})\n\ntarget_link_libraries(${PRJ_NAME} PUBLIC JNI::JNI JNI::AWT JNI::JVM)\n<\/pre><\/div>\n\n\n<p>Program w Javie mie\u015bci si\u0119 w klasie MyClass, w pliku MyClass.class. Jego pierwsza wersja jest pokazana poni\u017cej. Na pocz\u0105tku zawiera tylko pole o warto\u015bci ca\u0142kowitej \u2018value_\u2019 oraz konstruktor, kt\u00f3re je ustawia. Klasa b\u0119dzie rozbudowywana w miar\u0119 opisywania kolejnych zagadnie\u0144.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic class MyClass {\n  public MyClass(int value)\n  {\n    this.value_ = value;\n  }\n\n  int value_;\n}\n<\/pre><\/div>\n\n\n<p>Program nale\u017cy skompilowa\u0107 do pliku *.java&nbsp; poleceniem javac. W tym przypadku kod bajtowy znajdzie si\u0119 w tym samym katalogu co plik wykonywalny C++. Taka organizacja oddziela od siebie pliki \u017ar\u00f3d\u0142owe oraz binarne.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Przygotowanie \u015brodowiska<\/strong><\/h3>\n\n\n\n<p>Poni\u017cej znajdziecie kod aplikacji C++, kt\u00f3ra \u0142aduje \u015brodowisko Java oraz znajduje nasz\u0105 klas\u0119. Wszystkie potrzebne deklaracje zlokalizowane s\u0105 w pliku nag\u0142\u00f3wkowym \u2018jni.h\u2019. Przygotowanie \u015brodowiska wymaga kilku krok\u00f3w wi\u0119cej w por\u00f3wnaniu do Pythona.<\/p>\n\n\n\n<p>Jednym z ustawianych parametr\u00f3w jest opcja \u2018java.class.path\u2019, do kt\u00f3rej jest dodany katalog pliku wykonywalnego. Jest on wyznaczany z nazwy programu przekazywanej przez pierwszy argument, czyli argv[0]. Wywo\u0142anie JNI_CreateJavaVM() inicjalizuje zar\u00f3wno maszyn\u0119 wirtualn\u0105 Java, jak r\u00f3wnie\u017c \u015brodowisko uruchomieniowe. Wska\u017anik env daje nam dost\u0119p do ca\u0142ego szeregu funkcji umo\u017cliwiaj\u0105cych interakcj\u0119 z klasami.<\/p>\n\n\n\n<p>Jedn\u0105 z pierwszych operacji jest odszukanie naszej klasy za pomoc\u0105 funkcji FindClass(). Jest to konieczne, aby dosta\u0107 si\u0119 do wszystkich element\u00f3w, r\u00f3wnie\u017c metod statycznych. Po uruchomieniu programu zasoby s\u0105 czyszczone przez DestroyJavaVM().<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n#include &lt;jni.h&gt;\n#include &lt;filesystem&gt;\n#include &lt;fmt\/core.h&gt;\n\nint main(int argc, char *argv&#x5B;])\n{\n    const auto bin_dir {weakly_canonical(path(argv&#x5B;0])).parent_path()};\n    std::string java_opt {fmt::format(&quot;-Djava.class.path={}&quot;, bin_dir.string())};\n    \n    JavaVMOption options {\n        .optionString = const_cast&lt;char*&gt;(java_opt.c_str())\n    };\n    JavaVMInitArgs vm_args{ \n        .version = JNI_VERSION_1_8,\n        .nOptions = 1,\n        .options = &amp;options,\n        .ignoreUnrecognized = false\n    }; \n\n    JavaVM *jvm{};       \/* denotes a Java VM *\/\n    JNIEnv *env{};       \/* pointer to native method interface *\/\n    JNI_CreateJavaVM(&amp;jvm, (void**)&amp;env, &amp;vm_args);\n\n    jclass java_class = env-&gt;FindClass(&quot;MyClass&quot;);\n    if(java_class == nullptr)\n    {\n        fmt::print(&quot;Unable to find the class...\\n&quot;);\n        return -1;\n    }\n    jvm-&gt;DestroyJavaVM();\n    return 0;\n}\n<\/pre><\/div>\n\n\n<p>Je\u017celi nie nast\u0105pi b\u0142\u0105d \u0142adowania, to ten program nie wypisze nic na wyj\u015bcie. Jest przedstawiony jedynie w celu pokazania, jak wygl\u0105da proces ustawiania \u015brodowiska oraz odnajdywania klasy napisanej w Javie.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic void print() {\n      System.out.println(&quot;&#x5B;JAVA]: Value &quot; + this.value_);\n  }\n  \n  public String get_string() {\n    String returned_string = &quot;Za\u017c\u00f3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144&quot;;\n    System.out.println(&quot;&#x5B;JAVA]: Returning string &#039;&quot; + returned_string + &quot;&#039; with len: &quot; + returned_string.length());\n    return returned_string;\n  }\n\n  public void print_string(String s) {\n    System.out.println(&quot;&#x5B;JAVA]: &#039;&quot; + s + &quot;&#039;&quot;);\n  }\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Java \u2013 pierwsze uruchomienie<\/strong><\/h2>\n\n\n\n<p>Dost\u0119p i uruchamianie funkcji napisanych w Javie jest nieco bardziej z\u0142o\u017cone, ni\u017c by\u0142o to z programem w Pythonie. Nale\u017cy zwr\u00f3ci\u0107 uwag\u0119 na dopasowanie sygnatury do wyszukiwanego obiektu. Dzieje si\u0119 tak, poniewa\u017c <strong>Java jest j\u0119zykiem o typowaniu statycznym. Oznacza to, \u017ce ka\u017cda zmienna i metoda musi mie\u0107 typ ustalony w momencie tworzenia programu<\/strong>. W tym przypadku skupimy si\u0119 na uruchomieniu funkcji statycznej \u2018test()\u2019<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic class MyClass {\n  \/\/ ... class definition ...\n  static public void test() {\n    System.out.println(&quot;&#x5B;JAVA]: test&quot;);\n  }\n}\n<\/pre><\/div>\n\n\n<p>W Javie wszystkie funkcje, nawet statyczne, musz\u0105 nale\u017ce\u0107 do jakiej\u015b klasy. \u017beby znale\u017a\u0107 tak\u0105 funkcj\u0119, trzeba pos\u0142u\u017cy\u0107 si\u0119 funkcj\u0105 GetStaticMethodID(). Jako parametry przyjmuje ona identyfikator klasy, nazw\u0119 szukanej funkcji oraz jej sygnatur\u0119. Sk\u0142ada si\u0119 ona z ci\u0105gu znak\u00f3w, w kt\u00f3rym zakodowany jest zestaw przekazywanych parametr\u00f3w. Wewn\u0105trz nawias\u00f3w znajduj\u0105 si\u0119 parametry funkcji, a za nimi typ zwracanej warto\u015bci. Funkcja \u2018test()\u2019 nie przyjmuje ani nie zwraca \u017cadnych warto\u015bci, dlatego nawiasy s\u0105 puste, a zwracany typ \u2018void\u2019 jest symbolizowany znakiem V. &nbsp;<\/p>\n\n\n\n<p>Opis tego, jak r\u00f3\u017cne typy s\u0105 reprezentowane w sygnaturze, wraz z podsumowaniem w tabeli, znajduj\u0105 si\u0119 w dalszej cz\u0119\u015bci artyku\u0142u.<\/p>\n\n\n\n<p>Je\u017celi pasuj\u0105ca funkcja nie zostanie znaleziona, to zostanie zwr\u00f3cony pusty wska\u017anik \u2018NULL\u2019. Do uruchomienia znalezionej funkcji s\u0142u\u017cy procedura \u2018CallStaticVoidMethod()\u2019, kt\u00f3ra przyjmuje na wej\u015bciu identyfikator klasy oraz wcze\u015bniej znaleziony identyfikator funkcji.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\njclass java_class = env-&gt;FindClass(&quot;MyClass&quot;);\n    jmethodID test_id = env-&gt;GetStaticMethodID(java_class, &quot;test&quot;, &quot;()V&quot;);\n    env-&gt;CallStaticVoidMethod(java_class, test_id);\n<\/pre><\/div>\n\n\n<p>Po uruchomieniu aplikacji \u2018java_test\u2019, na ekranie powinien pojawi\u0107 si\u0119 nast\u0119puj\u0105cy tekst wypisywany przez wywo\u0142an\u0105 funkcj\u0119:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"399\" height=\"36\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz6.png\" alt=\"kod\" class=\"wp-image-30991\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz6.png 399w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz6-300x27.png 300w\" sizes=\"(max-width: 399px) 100vw, 399px\" \/><\/figure>\n\n\n\n<p><strong>Bardziej dociekliwy czytelnik zwr\u00f3ci uwag\u0119 na specyficzn\u0105 nazw\u0119 funkcji<\/strong> u\u017cytej do wywo\u0142ania funkcji. Zawiera ona w swojej nazwie zar\u00f3wno informacj\u0119 o tym, \u017ce wywo\u0142ywana funkcja jest statyczna, oraz \u017ce zwraca typ \u2018void\u2019. Jest to kolejna rzecz, kt\u00f3ra musi si\u0119 zgadza\u0107 z typem wywo\u0142ywanej procedury.<\/p>\n\n\n\n<p>Spr\u00f3bujmy zatem wywo\u0142a\u0107 bardziej skomplikowan\u0105 funkcj\u0119 add_one(), kt\u00f3ra przyjmuje i zwraca typ ca\u0142kowity.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic class MyClass {\n  \/\/ ... class definition ...\n  static public int add_one(int a){\n    int b = a + 1;\n    return b;\n  }\n}\n<\/pre><\/div>\n\n\n<p>Typ \u2018int\u2019 z Javy jest reprezentowany przez \u2018jint\u2019 w j\u0119zyku C++. Jest on typem prostym, czyli w trakcie jego tworzenia pami\u0119\u0107 nie jest alokowana dynamicznie. Wystarczy stworzy\u0107 zmienn\u0105 lokaln\u0105 i mo\u017cna jej przypisa\u0107 rezultat wywo\u0142ania funkcji. Poni\u017cszy kod dodatkowo wypisuje jego rozmiar.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\njmethodID add_one_id = env-&gt;GetStaticMethodID(java_class, &quot;add_one&quot;, &quot;(I)I&quot;);\n    jint value{42};\n    jint result = env-&gt;CallStaticIntMethod(java_class, add_one_id, value);\n    fmt::print(&quot;Function returned {}, sizeof(jint) = {}\\n&quot;, result,   sizeof(jint));\n<\/pre><\/div>\n\n\n<p>Wynik dzia\u0142ania programu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"392\" height=\"34\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz7.png\" alt=\"kod\" class=\"wp-image-30993\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz7.png 392w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz7-300x26.png 300w\" sizes=\"(max-width: 392px) 100vw, 392px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Typy Java i ich w\u0142a\u015bciwo\u015bci<\/strong><\/h3>\n\n\n\n<p>Podsumowanie typ\u00f3w Java i ich w\u0142a\u015bciwo\u015bci znajduje si\u0119 w poni\u017cszej tabeli. Ka\u017cdemu typowi jest przyporz\u0105dkowany kod u\u017cywany w sygnaturze oraz osobna funkcja s\u0142u\u017c\u0105ca do wywo\u0142ania funkcji. Poszczeg\u00f3lne funkcje r\u00f3\u017cni\u0105 si\u0119 typem zwracanej warto\u015bci. Je\u017celi chcemy wywo\u0142a\u0107 funkcj\u0119 statyczn\u0105, nale\u017cy doda\u0107 do nazwy prefiks <em>CallStatic <\/em>zamiast samego <em>Call<\/em>, jak w powy\u017cszym przyk\u0142adzie.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Typ<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Bity\/Znak<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Typ Java<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Kod parametru<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Wywo\u0142anie<\/strong><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">void<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">V<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallVoidMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Boolean<\/td><td class=\"has-text-align-center\" data-align=\"center\">8\/U<\/td><td class=\"has-text-align-center\" data-align=\"center\">jboolean<\/td><td class=\"has-text-align-center\" data-align=\"center\">Z<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallBooleanMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">byte<\/td><td class=\"has-text-align-center\" data-align=\"center\">8\/S<\/td><td class=\"has-text-align-center\" data-align=\"center\">jbyte<\/td><td class=\"has-text-align-center\" data-align=\"center\">B<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallByteMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">char<\/td><td class=\"has-text-align-center\" data-align=\"center\">16\/U<\/td><td class=\"has-text-align-center\" data-align=\"center\">jchar<\/td><td class=\"has-text-align-center\" data-align=\"center\">C<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallCharMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">short<\/td><td class=\"has-text-align-center\" data-align=\"center\">16\/S<\/td><td class=\"has-text-align-center\" data-align=\"center\">jshort<\/td><td class=\"has-text-align-center\" data-align=\"center\">S<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallShortMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">int<\/td><td class=\"has-text-align-center\" data-align=\"center\">32\/S<\/td><td class=\"has-text-align-center\" data-align=\"center\">jint<\/td><td class=\"has-text-align-center\" data-align=\"center\">I<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallIntMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">long<\/td><td class=\"has-text-align-center\" data-align=\"center\">64\/S<\/td><td class=\"has-text-align-center\" data-align=\"center\">jlong<\/td><td class=\"has-text-align-center\" data-align=\"center\">J<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallLongMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">float<\/td><td class=\"has-text-align-center\" data-align=\"center\">32<\/td><td class=\"has-text-align-center\" data-align=\"center\">jfloat<\/td><td class=\"has-text-align-center\" data-align=\"center\">F<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallFloatMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">double<\/td><td class=\"has-text-align-center\" data-align=\"center\">64<\/td><td class=\"has-text-align-center\" data-align=\"center\">jdouble<\/td><td class=\"has-text-align-center\" data-align=\"center\">D<\/td><td class=\"has-text-align-center\" data-align=\"center\">CallDoubleMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Java Class<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">L fully-qualified-class<strong>;<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\">CallObjectMethod<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Tablica []<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">\u2013<\/td><td class=\"has-text-align-center\" data-align=\"center\">[ type <em>(sic!)<\/em><\/td><td class=\"has-text-align-center\" data-align=\"center\">CallObjectMethod<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Tab. 1 Podsumowanie typ\u00f3w Java i ich w\u0142a\u015bciwo\u015bci<\/figcaption><\/figure>\n\n\n\n<p>Wyja\u015bnienia mo\u017ce jeszcze wymaga\u0107 to, <strong>jak stworzy\u0107 sygnatur\u0119 bardziej skomplikowanej funkcji<\/strong>.<\/p>\n\n\n\n<p>Typy podstawowe s\u0105 reprezentowane przez pojedyncze wielkie litery. Je\u017celi jest ich wi\u0119cej, to wyst\u0119puj\u0105 one bezpo\u015brednio po sobie, be\u017c \u017cadnych przerw czy separator\u00f3w. Je\u015bli parametr jest tablic\u0105, to jego kod jest poprzedzany <strong>jednym<\/strong> znakiem \u2018[\u2018. Jest to troch\u0119 nieintuicyjne, ale nie ma tam nawiasu zamykaj\u0105cego. Natomiast w przypadku typ\u00f3w obiektowych identyfikator zaczyna si\u0119 od litery \u2018L\u2019, a nast\u0119pnie jest podana pe\u0142na nazwa typu. Jego definicja ko\u0144czy si\u0119 znakiem \u015brednika.<\/p>\n\n\n\n<p>Na przyk\u0142ad poni\u017csza funkcja: &nbsp;<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\nlong f (int n, String s, int&#x5B;] arr);\n<\/pre><\/div>\n\n\n<p>powinna zosta\u0107 wyszukana za pomoc\u0105 identyfikatora:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n(ILjava\/lang\/String;&#x5B;I)J\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>Tworzenie Instancji Obiektu<\/strong><\/h3>\n\n\n\n<p>Kolejnym krokiem jest stworzenie instancji obiektu. Jako \u017ce zaczynamy operowa\u0107 na typach obiektowych, to nie nale\u017cy pomija\u0107 zwalniania zasob\u00f3w w momencie zako\u0144czenia \u017cycia instancji obiektu.<\/p>\n\n\n\n<p>Robi si\u0119 to za pomoc\u0105 funkcji DeleteLocalRef(). Analogicznie do przypadku Pythona, proponuj\u0119 stworzy\u0107 prosty dealokator zasob\u00f3w w postaci specjalizowanego smart pointera, kt\u00f3ry prezentuj\u0119 na poni\u017cszym listingu.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\nauto ref_deleter = &#x5B;&amp;env](jobject obj){\n        env-&gt;DeleteLocalRef(obj);\n    };\n    using JavaRefUniquePtr = std::unique_ptr&lt;std::remove_pointer_t&lt;jobject&gt;, decltype(ref_deleter)&gt;;\n<\/pre><\/div>\n\n\n<p>W odr\u00f3\u017cnieniu od poprzedniego przypadku, nie jest on bezstanowy. Lambda musi przechowywa\u0107 wska\u017anik na wcze\u015bniej zainicjalizowane \u015brodowisko uruchomieniowe env. <strong>Mo\u017cna by tego unikn\u0105\u0107, deklaruj\u0105c t\u0105 zmienn\u0105 jako globaln\u0105, ale nie uznaj\u0119 tego za rozwi\u0105zanie eleganckie<\/strong>.<\/p>\n\n\n\n<p>Pod typem jobject znajduje si\u0119 tak naprawd\u0119 wska\u017anik, kt\u00f3ry jest usuwany szablonem remove_pointer_t. Ze wzgl\u0119du na przechowywany stan, lambd\u0119 nale\u017cy r\u00f3wnie\u017c podawa\u0107 jako parametr podczas tworzenia nowych instancji wska\u017anik\u00f3w. <strong>Nale\u017cy zwr\u00f3ci\u0107 uwag\u0119 na to, \u017ceby dokona\u0107 wszystkich dealokacji<\/strong> przed wywo\u0142aniem DestroyJavaVM() na ko\u0144cu programu. Taka pomy\u0142ka mo\u017ce si\u0119 zdarzy\u0107 szczeg\u00f3lnie w przypadku prostszych program\u00f3w, kt\u00f3re mieszcz\u0105 si\u0119 w jednej funkcji. Wtedy zasi\u0119g zmiennej automatycznej mo\u017ce si\u0119ga\u0107 poza to wywo\u0142anie, co spowoduje wyst\u0105pienie wyj\u0105tku i obszerny komunikat w konsoli.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\njmethodID constructor = env-&gt;GetMethodID(java_class, &quot;&lt;init&gt;&quot;, &quot;(I)V&quot;);\n    jint value{7};\n    JavaRefUniquePtr java_object \n             {env-&gt;NewObject(java_class, constructor, value), ref_deleter};\n    jmethodID method_id = env-&gt;GetMethodID(java_class, &quot;print&quot;, &quot;()V&quot;);\n    env-&gt;CallVoidMethod(java_object.get(), method_id);\n    \/\/ Directly access field in the class\n    jfieldID field_id = env-&gt;GetFieldID(java_class, &quot;value_&quot;, &quot;I&quot;);\n    jint current_value{env-&gt;GetIntField(java_object.get(), field_id)};\n    fmt::print(&quot;Current value: {}\\n&quot;, current_value);\n    env-&gt;SetIntField(java_object.get(), field_id, current_value + 1);\n    env-&gt;CallVoidMethod(java_object.get(), method_id);\n<\/pre><\/div>\n\n\n<p>\u017beby stworzy\u0107 nowy obiekt, nale\u017cy odnale\u017a\u0107 konstruktor, kt\u00f3ry jest funkcj\u0105 specjaln\u0105 o nazwie &lt;init&gt;. Posiada on sygnatur\u0119 zgodn\u0105 z definicj\u0105 \u2013 w tym przypadku przyjmuje jedn\u0105 warto\u015b\u0107 typu integer. Nast\u0119pnie przekazuje si\u0119 go do funkcji, kt\u00f3ra tworzy nowy obiekt \u2013 NewObject(). Potem wystarczy wyszuka\u0107 interesuj\u0105c\u0105 nas metod\u0119 i j\u0105 wywo\u0142a\u0107. Potrzebna jest do tego zar\u00f3wno instancja obiektu, jak r\u00f3wnie\u017c identyfikator metody.<\/p>\n\n\n\n<p>Kolejne linie programu pokazuj\u0105, jak mo\u017cna si\u0119 dosta\u0107 do p\u00f3l w klasie. S\u0142u\u017cy do tego metoda GetFieldID(), kt\u00f3ra przyjmuje nazw\u0119 pola oraz jego typ zakodowany w znany ju\u017c spos\u00f3b. Warto\u015b\u0107 pola mo\u017cna pobra\u0107 albo ustawi\u0107 odpowiednim wariantem funkcji Get\/SetField(). Ponowne uruchomienie metody print() udowadnia to, \u017ce warto\u015b\u0107 pola si\u0119 zmieni\u0142a.<\/p>\n\n\n\n<p>Po wywo\u0142aniu, funkcja z Javy powinna wypisa\u0107 na ekran:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"406\" height=\"52\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz8.png\" alt=\"kod\" class=\"wp-image-30995\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz8.png 406w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz8-300x38.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz8-400x52.png 400w\" sizes=\"(max-width: 406px) 100vw, 406px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Typ znakowy string<\/strong><\/h3>\n\n\n\n<p>Jednym z najpopularniejszych obiekt\u00f3w pojawiaj\u0105cych si\u0119 ju\u017c w najprostszych programach s\u0105 zmienne znakowe typu string. Przyk\u0142ad zwracania takiej warto\u015bci przez funkcj\u0119 jest pokazany na poni\u017cszym listingu.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\njmethodID method_id = env-&gt;GetMethodID(java_class, &quot;get_string&quot;, &quot;()Ljava\/lang\/String;&quot;);\n    JavaRefUniquePtr obj {env-&gt;CallObjectMethod(java_object.get(), method_id), ref_deleter};\n    jstring java_string = static_cast&lt;jstring&gt;(obj.get());\n    const char* c_str = env-&gt;GetStringUTFChars(java_string, nullptr);\n    fmt::print(&quot;Received from Java: &#039;{}&#039; \\n&quot;, c_str);\n    fmt::print(&quot;Java string UTFLength {}\\n&quot;, env-&gt;GetStringUTFLength(java_string));\n    fmt::print(&quot;Java string Length {}\\n&quot;, env-&gt;GetStringLength(java_string));\n    fmt::print(&quot;std::strlen {}\\n&quot;, std::strlen(c_str));\n    env-&gt;ReleaseStringUTFChars(java_string, c_str);\n<\/pre><\/div>\n\n\n<p>Ze stringami wsp\u00f3\u0142pracuj\u0105 specjalne funkcje, ale konieczne jest wcze\u015bniejsze rzutowanie wska\u017anika na typ jstring. Przyk\u0142adowy string zawiera znaki spoza podstawowego zestawu ASCII, jednak nie jest to problem, gdy\u017c Java u\u017cywa kodowania UTF do jednoznacznego reprezentowania ci\u0105g\u00f3w znakowych. Jeden znak na ekranie mo\u017ce zajmowa\u0107 wi\u0119cej ni\u017c jeden bajt, co nale\u017cy wzi\u0105\u0107 pod uwag\u0119 np. rezerwuj\u0105c bufor.<\/p>\n\n\n\n<p>Z tego powodu istniej\u0105 <strong>dwa sposoby sprawdzania d\u0142ugo\u015bci ci\u0105gu znakowego<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>funkcja GetStringLength() zwraca ilo\u015b\u0107 znak\u00f3w pojawiaj\u0105cych si\u0119 na ekranie,<\/li>\n\n\n\n<li>funkcja GetStringUTFChars() oblicza zaj\u0119to\u015b\u0107 bufora przez dan\u0105 zmienn\u0105 i pokrywa si\u0119 z wynikiem zwracanym przez funkcj\u0119 biblioteki standardowej strlen().<\/li>\n<\/ul>\n\n\n\n<p>\u017beby dosta\u0107 si\u0119 do bufora z danymi stringa, nale\u017cy wywo\u0142a\u0107 GetStringUTFChars(), kt\u00f3ra zwr\u00f3ci wska\u017anik typu char*. Po takim \u017c\u0105daniu dost\u0119pu do bufora nie nale\u017cy zapomnie\u0107 o jego r\u0119cznym zwolnieniu za pomoc\u0105 ReleaseStringUTFChars().<\/p>\n\n\n\n<p>Wynik dzia\u0142ania programu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"433\" height=\"83\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz9.png\" alt=\"kod\" class=\"wp-image-30997\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz9.png 433w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz9-300x58.png 300w\" sizes=\"(max-width: 433px) 100vw, 433px\" \/><\/figure>\n\n\n\n<p>W\u0142asnor\u0119czne stworzenie takiej zmiennej r\u00f3wnie\u017c nie nastr\u0119cza trudno\u015bci. Wystarczy wywo\u0142a\u0107 funkcj\u0119 NewStringUTF(), kt\u00f3ra zwr\u00f3ci wska\u017anik na nowo stworzon\u0105 zmienn\u0105 wype\u0142nion\u0105 przekazanym tekstem. Nie nale\u017cy zapomnie\u0107 o analogicznym zwolnieniu zasob\u00f3w obiektu za pomoc\u0105 DeleteLocalRef(). Tak stworzony string mo\u017cna przekaza\u0107 do funkcji w naszej klasie print_string(), kt\u00f3ra wypisze go do konsoli.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\njmethodID method_id = env-&gt;GetMethodID(java_class, &quot;print_string&quot;, &quot;(Ljava\/lang\/String;)V&quot;);\n    const char* c_str = &quot;Hello from C++!&quot;;\n    jstring java_string = env-&gt;NewStringUTF(c_str);\n    env-&gt;CallVoidMethod(java_object.get(), method_id, java_string);\n    env-&gt;DeleteLocalRef(java_string);\n<\/pre><\/div>\n\n\n<p>Na ekranie pojawi si\u0119:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"220\" height=\"17\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Obraz10.png\" alt=\"kod\" class=\"wp-image-30999\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Artyku\u0142 poruszy\u0142 jedynie podstawy zagadnienia wsp\u00f3\u0142pracy pomi\u0119dzy C\/C++ oraz j\u0119zykami wy\u017cszego poziomu. Moim zdaniem <strong>po\u0142\u0105czenie dw\u00f3ch j\u0119zyk\u00f3w w jednej aplikacji jest zagadnieniem ciekawym samym w sobie.<\/strong><\/p>\n\n\n\n<p>Zg\u0142\u0119bianie nietypowych temat\u00f3w pozwala na <strong>zapoznanie si\u0119 ze technicznymi niuansami<\/strong>, kt\u00f3rych mo\u017ce nawet nie byliby\u015bmy \u015bwiadomi bez tego \u0107wiczenia. Czytanie dokumentacji oraz \u0142\u0105czenie r\u00f3\u017cnych \u015brodowisk pozwoli\u0142o mi lepiej pozna\u0107 szczeg\u00f3\u0142y dzia\u0142ania zar\u00f3wno j\u0119zyka Python jak i Java.<\/p>\n\n\n\n<p>Je\u017celi chodzi o <strong>praktyczne zastosowania prezentowanych rozwi\u0105za\u0144<\/strong>, to jednym z nich jest u\u017cycie bibliotek, kt\u00f3re akurat nie s\u0105 dost\u0119pne pod konkretn\u0105 platform\u0105 programistyczn\u0105. W takim wypadku ich przepisywanie i p\u00f3\u017aniejsze utrzymywanie nie jest konieczne. Inn\u0105 opcj\u0105 jest danie mo\u017cliwo\u015bci u\u017cytkownikowi na rozszerzanie aplikacji poprzez pluginy napisane np. w Pythonie. J\u0119zyk ten jest popularny i bezpieczniejszy, poniewa\u017c zmniejsza ryzyko pope\u0142nienia b\u0142\u0119d\u00f3w zwi\u0105zanych z zarz\u0105dzaniem zasobami.<\/p>\n\n\n\n<p>Mam nadziej\u0119, \u017ce opisywany temat zadzia\u0142a\u0142 inspiruj\u0105co i <strong>pokaza\u0142 nowe metody rozwi\u0105zywania r\u00f3\u017cnych problem\u00f3w, kt\u00f3re napotykamy na co dzie\u0144 jako programi\u015bci<\/strong>. Dalsze zg\u0142\u0119bianie tych zagadnie\u0144 jest u\u0142atwione przez bogat\u0105 dokumentacj\u0119.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/oferty-pracy\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"737\" height=\"170\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/05\/praca-m.jpg\" alt=\"oferty pracy\" class=\"wp-image-31062\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/05\/praca-m.jpg 737w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/05\/praca-m-300x69.jpg 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Odno\u015bniki<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/python.readthedocs.io\/en\/stable\/extending\/embedding.html\" target=\"_blank\" rel=\"noopener\" title=\"\" rel=\"nofollow\" >Embedding Python in Another Application<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.boost.org\/doc\/libs\/1_78_0\/libs\/python\/doc\/html\/tutorial\/index.html\" target=\"_blank\" rel=\"noopener\" title=\"\" rel=\"nofollow\" >Boost.Python<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/technotes\/guides\/jni\/spec\/jniTOC.html\" target=\"_blank\" rel=\"noopener\" title=\"\" rel=\"nofollow\" >Java Native Interface Specification<\/a><\/li>\n<\/ul>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u015bli interesuje Ci\u0119 tematyka embedded, zajrzyj r\u00f3wnie\u017c <a href=\"https:\/\/sii.pl\/blog\/all\/embedded\/\" target=\"_blank\" rel=\"noopener\" title=\"\">do innych artyku\u0142\u00f3w naszych ekspert\u00f3w<\/a> \ud83d\ude42<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;30980&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 6)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Jak si\u0119 dogada\u0107 z innymi j\u0119zykami? Wywo\u0142ywanie obcych funkcji w kodzie C\\\/C++&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 6)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Wiele programist\u00f3w, szczeg\u00f3lnie wywodz\u0105cych si\u0119 ze \u015brodowiska embedded, specjalizuje si\u0119 w j\u0119zykach C\/C++. W tym artykule zach\u0119cam do wyj\u015bcia poza &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/jak-sie-dogadac-z-innymi-jezykami-wywolywanie-obcych-funkcji-w-kodzie-c-c\/\">Continued<\/a><\/p>\n","protected":false},"author":711,"featured_media":31003,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1512,563,1058,330,584],"class_list":["post-30980","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-poradnik","tag-embedded","tag-cpp","tag-java","tag-python"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2025\/04\/Poradnikowy.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30980"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/711"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=30980"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30980\/revisions"}],"predecessor-version":[{"id":31064,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/30980\/revisions\/31064"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/31003"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=30980"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=30980"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=30980"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}