abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 00:55 | Pozvánky

    Začal semestr, začal i podzim a kromě hub rostou jako po dešti i veřejné dílny v Praze. Nedávno strahováci referovali o hackerspacu Bordel, nyní se otevřela dílna Dejvice Lab jen kousek od ČVUT. Na blížící Virtuální Bastlírně tak uslyšíte nejen report z návštěvy dílny HWLab, ale i řadu novinek, událostí a úsměvných momentů, které se za poslední měsíc ve světě techniky, ale i vědy udály. Připojte se tedy již v úterý 13.10. od 20:00 a zapojte se do

    … více »
    bkralik | Komentářů: 0
    včera 11:33 | Nová verze

    Byl vydán LineageOS 24 (Mastodon). LineageOS (Wikipedie) je svobodný operační systém pro chytré telefony, tablety a set-top boxy založený na Androidu. Jedná se o nástupce CyanogenModu. LineageOS 24 je založený na Androidu 17.

    Ladislav Hagara | Komentářů: 0
    včera 03:55 | IT novinky

    Společnost Valve publikovala na svém GitLabu nákresy a schémata zapojení headsetu Steam Frame. Pro nekomerční účely.

    Ladislav Hagara | Komentářů: 1
    10.10. 23:11 | Bezpečnostní upozornění

    Soutěž Pwn2Own Ireland 2026 skončila 9. října. Bezpečnostní výzkumníci získali celkem 1 262 000 dolarů na odměnách. Během soutěže bylo předvedeno zneužití 98 zero-day zranitelností. Testování zahrnovalo různé kategorie zařízení a software. Výzkumníci předváděli prakticky fungující útoky podle pravidel soutěže. Výsledky následně slouží výrobcům při přípravě oprav. Mezi pokořenými jsou: Samsung Galaxy S26, OpenAI Codex, Oracle Autonomous AI Database, Google Pixel 10, u iPhone 17 neuspěli.

    vencour | Komentářů: 0
    9.10. 22:44 | Nová verze

    Programovací jazyk Python byl vydán v nové verzi 3.15.0. Podrobný přehled novinek v aktualizované dokumentaci.

    Ladislav Hagara | Komentářů: 19
    9.10. 22:33 | Zajímavý projekt

    BIGWORDS.PAGE je open-source webová aplikace, která po otevření odkazu v prohlížeči vykreslí přes celou obrazovku jednoduché informační sdělení. Zpráva i její nastavení jsou uložené v části URL za znakem #, například odkaz https://bigwords.page/#abclinuxu zobrazí jako velký bílý nápis 'abclinuxu' na černém pozadí. Obsah odkazu lze upravovat i vestavěným editorem, ten umožňuje nastavovat formátování a vizuální efekty textu, časovače, QR kódy a obrázky. Zdrojový kód je dostupný pod licencí MIT na GitHubu.

    ❗Červivý Hřib krade❗ | Komentářů: 9
    9.10. 11:55 | Upozornění

    V neděli 11. října proběhne rotace klíče kořenové zóny. Podruhé v historii. Ondřej Filip na blogu CZ.NIC: "Pokud je pro Vás DNS protokol spíše výzva, ale přesto spravujete nějakou síť či DNS resolver, zkuste si jednoduchý test, který připravila firma Cloudflare na této adrese. Obzvláště zbystřit byste měli, pokud uvidíte nějaká červená políčka."

    Ladislav Hagara | Komentářů: 14
    9.10. 09:55 | IT novinky

    Vláda Spojených států se rozhodla vyřadit americkou softwarovou společnost Microsoft a několik dalších velkých technologických podniků z programu, který umožňuje kvalifikovaným zahraničním pracovníkům získat povolení k trvalému pobytu. Oznámila to včera administrativa amerického prezidenta Donalda Trumpa. Opatření zdůvodnila rozsáhlým zneužíváním programu, který je dlouhodobě terčem kritiky ze strany Trumpových příznivců, neboť prý znevýhodňuje americké pracovníky.

    Ladislav Hagara | Komentářů: 12
    9.10. 09:44 | IT novinky

    Datové centrum největší ruské technologické společnosti Jandex v Rjazaňské oblasti se stalo cílem dronového útoku a zastavilo provoz. Jandexu se někdy přezdívá „ruský Google“. Provozuje nejoblíbenější internetový vyhledávač v Rusku nebo aplikace pro objednávky jídla a taxi. Využívají jej desítky milionů lidí v rusky mluvících zemích.

    Ladislav Hagara | Komentářů: 13
    9.10. 09:33 | Nová verze

    Francouzská společnost Mistral AI představila Mistral Large 4 (interně přezdívaný 'le Chonk', volně přeloženo 'pořádný macek'), 'open-weight multimodální hybridní instruct-and-reasoning model s architekturou granulárního MoE, nativně podporující více jak 160 jazyků'. Model má přes jeden bilión parametrů, z nichž při práci využívá 49 miliard, kontextové okno o délce milion tokenů a obrazový enkodér o 1,6 miliardách parametrů.

    … více »
    ❗Červivý Hřib krade❗ | Komentářů: 2
    Které desktopové prostředí na Linuxu používáte?
     (9%)
     (7%)
     (4%)
     (21%)
     (29%)
     (8%)
     (5%)
     (2%)
     (14%)
     (20%)
    Celkem 2832 hlasů
     Komentářů: 32, poslední včera 17:02
    Rozcestník

    PyPy a embedování do C/C++ aplikací

    11.3.2014 17:54 | Přečteno: 1106× | poslední úprava: 11.3.2014 17:54

    V práci jsme pro QA oddělení nakódili python plugin pro náš software, aby se už chudáci testeři nemuseli mořit s testováním na základě logů, do kterých jsou vyexportovány všechny data jako ASCII (takový log má klidně přes 100GB zagzippovaný, brr). Tento plugin se osvědčil, ale co si budeme povídat, CPython je pro zpracování velkého množství dat pomalý (a s LuaJIT mě šéf poslal někam ;-) ). Takže zkusíme embedovat PyPy ... no, byla to sranda už jen díky tomu, že jediná "dokumentace" jsou zdrojáky uwsgi PyPy pluginu. Naštěstí se nakonec ukázalo, že embedování PyPy je celkem fajn a následující řádky by měly posloužit jako dokumentace embedování PyPy do C (resp. C++) aplikací.

    Kompilace PyPy

    Ouch, bohužel PyPy v dnešních distribucích není zkompilováno s "--shared", takže je potřeba překompilovat. Naštěstí poslední oficiální release "--shared" podporuje, takže není potřeba řešit mercurial, ani žádné (pochybné) patche :-).

    Více informací o kompilaci (nejedná se o nic složitého, je ovšem potřeba asi 4GB volné ram) a především seznam závislostí zde
    wget https://bitbucket.org/pypy/pypy/downloads/pypy-2.2.1-src.tar.bz2
    tar xf pypy-2.2.1-src.tar.bz2
    cd pypy-2.2.1
    # Pozor, samotná kompilace PyPy vyžaduje PyPy (takže "aptitude install pypy", resp. alternativa pro vaší distribuci)
    ./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone 
    

    A embedujeme ... první příklad

    int main(int argc, char *argv[])
    {
        rpython_startup_code();
        pypy_execute_source("print('Hello World')\n");
        pypy_init_threads();
        return 0;
    }
    
    Stačí zkompilovat a spustit:
    gcc prvni_priklad.c -Lcesta_k_pypy -lpypy-c -o prvni_priklad
    LD_LIBRARY_PATH=cesta_k_pypy ./prvni_priklad
    

    Chybějící PyPy.h (pypy 2.2.1)

    Ve verzích >2.2.1 už PyPy.h bude, takže nebude potřeba takto stahovat.

    Pokud zkusíte překompilovat prvni_priklad.c pomocí g++, kompilace skončí s chybou (gcc -Wall také vypíše ekvivalentní warning), samozřejmě, funkce rpython_startup_code a pypy_execute_source nejsou deklarovány.

    Jak jsem v perexu zmiňoval, embedování PyPy je težce cutting-edge a v posledním stable vydání zatím není PyPy.h (ten byl přidán commitem c4cd6ec).

    Stačí tedy stáhnout PyPy.h z repositáře PyPy a umístit ho do adresáře include/

    cd cesta_k_pypy/include
    wget https://bitbucket.org/pypy/pypy/raw/c4cd6eca9358066571500ac82aaacfdaa3889e8c/include/PyPy.h
    

    Přidejte #include <PyPy.h> na začátek prvni_priklad.c a můžete překompilovat s g++

    g++ -Icesta_k_pypy/include -Wno-write-strings prvni_priklad.c -Lcesta_k_pypy -lpypy-c -o prvni_priklad
    LD_LIBRARY_PATH=cesta_k_pypy ./prvni_priklad
    

    Boilerplate

    Příklad "Hello World" sice funguje hezky, ale pro reálné využití zbývá vyřešit následující:

    1. Načíst python kód ze souboru
    2. Nastavit pypy_home (toto je potřeba, aby správně fungoval import)
    3. Použít CFFI jako mezivrstvu mezi C a Pythonem (pypy_execute_source by měl být zavolán pouze jednou)

    Dále ukážu můj boilerplate pro první dva problémy, CFFI je kapitola sama pro sebe.

    Moje řešení je trochu složitější a navíc je GNU (glibc) a Linux specifické, proto by se na něj neměl nikdo dívat.

    Načtení python kódu ze souboru

    Tady by bylo lepší alternativou použít build systém k vygenerování a hardkódování cesty k .py souboru.

    #include <string.h>
    #include <stdlib.h>
    #include <PyPy.h>
    #include <libgen.h>
    #include <stdio.h>
    
    // caller should free returned pointer to avoid memleaks
    char* change_basename(char* full_path,char* new_basename) {
        char* full_path_copy = strdup(full_path);
        char* dirpath = dirname(full_path_copy);
     
        size_t new_path_len = strlen(dirpath)+1+strlen(new_basename); // +1 because of "/"
        char* new_path = (char*)malloc( new_path_len+1 ); // +1 because of terminating NULL
        memset(new_path, 0, new_path_len+1);
        strcat(new_path, dirpath);
        strcat(new_path, "/");
        strcat(new_path, new_basename);
     
        free(full_path_copy);
        return new_path;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* get_path_to_pyfile() {
        // Linux only
        // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
        // http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
        char* buf = realpath("/proc/self/exe",NULL);
        if (buf == NULL) {
            return NULL;
        }
        char* py_file = change_basename(buf,"setup.py");
        free(buf);
        return py_file;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* load_python_source(char* filepath) {
        char *buffer;
        long input_file_size;
        FILE *input_file = fopen(filepath, "rb");
        if (input_file == NULL) {
            return NULL;
        }
        fseek(input_file, 0, SEEK_END);
        input_file_size = ftell(input_file);
        rewind(input_file);
        buffer = (char*)malloc(input_file_size * (sizeof(char))+1);
        memset(buffer, 0, input_file_size* (sizeof(char))+1);
        fread(buffer, sizeof(char), input_file_size, input_file);
        fclose(input_file);
        return buffer;
    }
    
    int main(int argc, char *argv[])
    {
        // PyPy initialization
     
        char* py_file = get_path_to_pyfile();
        if (!py_file) {
            printf("Error determining path to the  python setup file (setup.py)\n");
            exit(1);
        }
        char* buffer = load_python_source(py_file);
        if (!buffer) {
            printf("Error opening python setup file (setup.py)\n");
            exit(1);
        }
     
        // actual pypy initialization
        rpython_startup_code();
        pypy_execute_source( buffer );
        pypy_init_threads();
       
        // free stuff
        if (py_file != NULL) {
            free(py_file);
        }
        if (buffer != NULL) {
            free(buffer);
        }
        // end of PyPy initialization
    
        return 0;
    }
    

    Nastavení pypy_home

    Aby správně fungoval import, je potřeba před zavoláním funkce pypy_execute_source zavolat pypy_setup_home.

    Funkci pypy_setup_home je potřeba předat cestu k lib_pypy. Nenašel jsem způsob jak tuto cestu najít čistým způsobem (např. pomocí pkg-config) a proto následující glibc specifický hack.

    #if !(_GNU_SOURCE)
    #define _GNU_SOURCE
    #endif
     
    #include <stdio.h>
    #include <dlfcn.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <libgen.h>
    #include <PyPy.h>
    
    // caller should free returned pointer to avoid memleaks
    char* change_basename(char* full_path,char* new_basename) {
        char* full_path_copy = strdup(full_path);
        char* dirpath = dirname(full_path_copy);
     
        size_t new_path_len = strlen(dirpath)+1+strlen(new_basename); // +1 because of "/"
        char* new_path = (char*)malloc( new_path_len+1 ); // +1 because of terminating NULL
        memset(new_path, 0, new_path_len+1);
        strcat(new_path, dirpath);
        strcat(new_path, "/");
        strcat(new_path, new_basename);
     
        free(full_path_copy);
        return new_path;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* guess_pypyhome() {
        // glibc-only (dladdr is why we #define _GNU_SOURCE)
        // http://stackoverflow.com/questions/1681060/library-path-when-dynamically-loaded
        Dl_info info;
        void *_rpython_startup_code;
        _rpython_startup_code = dlsym(NULL,"rpython_startup_code");
        if (_rpython_startup_code == NULL) {
            return NULL;
        }
        if (dladdr(_rpython_startup_code, &info) != 0) {
            const char* lib_path = info.dli_fname;
            char* lib_realpath = realpath(lib_path, NULL);
            if (lib_realpath == NULL) {
                return NULL;
            }
            char* pypy_home = change_basename(lib_realpath,"pypy");
            free(lib_realpath);
            return pypy_home;
        }
        return NULL;
    }
    
    int main(int argc, char *argv[])
    {
        // PyPy initialization
        
        char* pypy_home = getenv("PYPY_HOME");
        int free_pypy_home = 0;
        if (pypy_home == NULL) {
            pypy_home = guess_pypyhome();
            free_pypy_home = 1;
        }
        if (!pypy_home) {
            printf("PYPY_HOME was not specified and PYPY_HOME autodetection failed\n");
            exit(1);
        }
        
        // actual pypy initialization
        rpython_startup_code();
        pypy_setup_home(pypy_home,1);
        pypy_execute_source("import cffi; print('Hello World')\n");
        pypy_init_threads();
       
        // free stuff
        if (free_pypy_home == 1 && pypy_home != NULL) {
            free(pypy_home);
        }
        return 0;
    }
    

    Také je potřeba linkovat oproti dl.

    g++ -Wno-write-strings priklad-pypy_set_home.c -Lcesta_k_pypy -lpypy-c -ldl -Icesta_k_pypy/include -o priklad-pypy_set_home
    

    CFFI

    Interface mezi PyPy a C kódem je nejlepší řešit pomocí CFFI (dokumentace). Funkci pypy_execute_source předáme python kód, který může nadefinovat callbacky apod.

    Kompletí příklad

    A nakonec kompletní ukázka jak nadefinovat a volat callback v PyPy (python kód) z C.

    priklad-pypy.c

    #if !(_GNU_SOURCE)
    #define _GNU_SOURCE
    #endif
    
    #include <stdio.h>
    #include <libgen.h>
    #include <dlfcn.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <PyPy.h>
    
    // caller should free returned pointer to avoid memleaks
    char* change_basename(char* full_path,char* new_basename) {
        char* full_path_copy = strdup(full_path);
        char* dirpath = dirname(full_path_copy);
    
        size_t new_path_len = strlen(dirpath)+1+strlen(new_basename); // +1 because of "/"
        char* new_path = (char*)malloc( new_path_len+1 ); // +1 because of terminating NULL
        memset(new_path, 0, new_path_len+1);
        strcat(new_path, dirpath);
        strcat(new_path, "/");
        strcat(new_path, new_basename);
    
        free(full_path_copy);
        return new_path;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* guess_pypyhome() {
        // glibc-only (dladdr is why we #define _GNU_SOURCE)
        // http://stackoverflow.com/questions/1681060/library-path-when-dynamically-loaded
        Dl_info info;
        void *_rpython_startup_code;
        _rpython_startup_code = dlsym(NULL,"rpython_startup_code");
        if (_rpython_startup_code == NULL) {
            return NULL;
        }
        if (dladdr(_rpython_startup_code, &info) != 0) {
            const char* lib_path = info.dli_fname;
            char* lib_realpath = realpath(lib_path, NULL);
            if (lib_realpath == NULL) {
                return NULL;
            }
            char* pypy_home = change_basename(lib_realpath,"pypy");
            free(lib_realpath);
            return pypy_home;
        }
        return NULL;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* load_python_source(char* filepath) {
        char *buffer;
        long input_file_size;
        FILE *input_file = fopen(filepath, "rb");
        if (input_file == NULL) {
            return NULL;
        }
        fseek(input_file, 0, SEEK_END);
        input_file_size = ftell(input_file);
        rewind(input_file);
        buffer = (char*)malloc(input_file_size * (sizeof(char))+1);
        memset(buffer, 0, input_file_size* (sizeof(char))+1);
        fread(buffer, sizeof(char), input_file_size, input_file);
        fclose(input_file);
        return buffer;
    }
    
    // caller should free returned pointer to avoid memleaks
    // returns NULL on error
    char* get_path_to_pyfile() {
        // Linux only
        // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe 
        // http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
        char* buf = realpath("/proc/self/exe",NULL);
        if (buf == NULL) {
            return NULL;
        }
        char* py_file = change_basename(buf,"setup.py");
        free(buf);
        return py_file;
    }
    
    void (*callback)(long);
    
    int main(int argc, char *argv[])
    {
        // PyPy initialization
    
        // prepare stuff
        char* pypy_home = getenv("PYPY_HOME");
        int free_pypy_home = 0;
        if (pypy_home == NULL) {
            pypy_home = guess_pypyhome();
            free_pypy_home = 1;
        }
        if (!pypy_home) {
            printf("PYPY_HOME was not specified and PYPY_HOME autodetection failed\n");
            exit(1);
        }
        char* py_file = get_path_to_pyfile();
        if (!py_file) {
            printf("Error determining path to the  python setup file (setup.py)\n");
            exit(1);
        }
        char* buffer = load_python_source(py_file);
        if (!buffer) {
            printf("Error opening python setup file (setup.py)\n");
            exit(1);
        }
    
        // actual pypy initialization
        rpython_startup_code();
        pypy_setup_home(pypy_home,1);
        pypy_execute_source( buffer );
        pypy_init_threads(); 
        // pypy_thread_attach(); // if multithreaded, call this in every thread which is calling into pypy
        
        // end of PyPy initialization
    
        for (int i=0; i<10; i++) {    
            callback(42);
        }
    
        // free stuff
        if (free_pypy_home == 1 && pypy_home != NULL) {
            free(pypy_home);
        }
        if (py_file != NULL) {
            free(py_file);
        }
        if (buffer != NULL) {
            free(buffer);
        }
    
        return 0;
    }
    

    Aby fungovaly callbacky s CFFI je potřeba překompilovat s flagem -export-dynamic

    g++ -Wno-write-strings priklad-pypy.c -Lcesta_k_pypy -lpypy-c -ldl -Icesta_k_pypy/include -o priklad-pypy -export-dynamic
    

    setup.py:

    V tomto příkladu mám kód přímo v callback funkci v setup.py, v reálném nasazení by setup.py fungoval pouze jako vrstva mezi C a pythonem a volal uživatelský kód v jiném modulu, který by už o žádném C nebo CFFI nevěděl.

    import os
    if "PYTHONPATH" in os.environ:
        import sys
        paths = os.environ["PYTHONPATH"].split(":")
        paths.reverse()
        for p in paths:
            sys.path.insert(0,p)
    
    import cffi
    ffi = cffi.FFI()
    ffi.cdef('void (*callback)(long);')
    lib = ffi.verify('void (*callback)(long);')
    def callback(i):
        print("yaay: %d" % i)
    cb = ffi.callback('void(long)',callback)
    lib.callback = cb
    
    LD_LIBRARY_PATH=cesta_k_pypy ./priklad-pypy
    

    Závěr

    Na první pohled se může zdát, že embedování PyPy do C je celkem složité, není tomu tak (vždyť kompletní příklad má kolem 150 řádků C kódu a většina z toho je copy&paste boilerplate). V mých (jednoduchých) testech jsem na problémy nenarazil, ale je potřeba mít na paměti, že embedování PyPy je těžce hipster feature.

           

    Hodnocení: 100 %

            špatné • dobré        

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    11.3.2014 18:31 Radek Podgorny | skóre: 16
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    k cemu konkretne ze to pouzivate? nejak v tom nevidim smysl.

    bez tech callbacku to vlastne jen imituje "vstupni" cast normalniho interpretu. stejny by bylo rovnou spustit 'pypy soubor.py', ne?

    a callbacky je mozne nacist z toho pythonu pomoci ctypes (nebo toho cffi?) a volat je primo (tedy jaksi embedovat c do pythonu), ne?

    nebo jsem uplne mimo? ;-)
    11.3.2014 18:52 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    Napriklad mas obrovskou C++ aplikaci a chces malou cast z ni implementovat v pythonu (resp. umoznit nekomu jinemu jeji rozsirovani pomoci pythonu). Klasika, napriklad skriptovani her. Tady resim jak pouzit misto CPythonu PyPy, protoze je mnohem rychlejsi (JIT).
    11.3.2014 19:51 psio
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    Byly by nejake benchmarky, ze se ty komplikace s PyPy vyplatili ? Ja mam bohuzel zkusenost, ze pro nas to byla ztrata casu a na testech nam to davalo +/- stejne vysledky jako klasicky CPython a ne jenom u kodu, kterej byl brzdenej komunikaci s databazi. S rychlosti behu LuaJIT 2.x se to vubec neda srovnavat. To uz je fakt lepsi to nejnutnejsi nakodit v C, Python ma k dispozici celkem slusny rozhrani jako cffi. Alternativne v Cythonu, pokud lze resit pouzitim ceckovych datovych typu.

    11.3.2014 20:44 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    Zrovna u tohohle jsme zkoncili zpatky u CPythonu (+posunuti vice kodu do C++) ;-). Protoze co se tyka interface python<->c++ tak (muj) cffi kod + pypy byl pomalejsi nez CPython a jeho nativni API. A samotne testy, ktere jsou napsane v pythonu jsou velice light-weight, takze PyPy vlastne moc nepomuze, ale v jinych situacich (pokud chcete embedovat narocnejsi python kod) verim ze pomuze dost - na LuaJIT to vykonem samozrejme mit nebude.

    Na druhou stranu, kolegovy jeho kod bezi nekolikanasobne rychleji jen diky tomu ze ho pusti pomoci pypy misto cpythonu (a navic nepotreboval embedovat, takze zadne komplikace) ... takze fakt zalezi jak kdy.
    Jardík avatar 12.3.2014 00:21 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    char* change_basename(char* full_path,char* new_basename) {
        char* full_path_copy = strdup(full_path);
        char* dirpath = dirname(full_path_copy);
      
        size_t new_path_len = strlen(dirpath)+1+strlen(new_basename); // +1 because of "/"
        char* new_path = (char*)malloc( new_path_len+1 ); // +1 because of terminating NULL
        memset(new_path, 0, new_path_len+1);
        strcat(new_path, dirpath);
        strcat(new_path, "/");
        strcat(new_path, new_basename);
      
        free(full_path_copy);
        return new_path;
    }
    
    Proč full_patch a new_basename není char const*? Žádný z nich nemodifikujete a pro full_patch stejně děláte kopii. Ten memset je totálně zbytečnej, použití strcat, když už znáte délky řetězců z předchozích volání, je pitomost. No ono i ta zbytečná kopie full_path je pitomost daná použití stupidní fce, která se nehodí.
    Věřím v jednoho Boha.
    12.3.2014 01:10 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    Proč full_patch a new_basename není char const*?
    Protoze jsem maslo, tohle si fixnu.
    Ten memset je totálně zbytečnej
    Ano je, ale nicemu nevadi protoze se zavola behem behu programu asi dvakrat. Btw. kdybych ho jen vyhodil, tak ten c string nekonci \0. Ale chapu jak to myslis.
    použití strcat, když už znáte délky řetězců z předchozích volání, je pitomost.
    hmmm?
    No ono i ta zbytečná kopie full_path je pitomost daná použití stupidní fce
    Co jsem mel pouzit misto dirname? :-/
    Jardík avatar 12.3.2014 03:29 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: PyPy a embedování do C/C++ aplikací
    Btw. kdybych ho jen vyhodil, tak ten c string nekonci \0
    Stačí ti nastavit první byte na 0 pro první strcat(), ten ti nakonec dá další nulu pro další strcat(), ... ale jestli to voláš 2x, ok.
    hmmm?
    char* full_path_copy = strdup(full_path);
    char* dirpath = dirname(full_path_copy);
    
    size_t dirpath_len = strlen(dirpath);
    size_t new_basename_len = strlen(new_basename);
    size_t new_path_len = dirpath_len + new_basename_len + 1;
    
    char* new_path = (char*)malloc( new_path_len+1 );
    memcpy(new_path, dirpath, dirpath_len);
    new_path[dirpath_len] = '/';
    memcpy(new_path+dirpath_len+1, new_basename, new_basename_len);
    new_path[new_path_len] = 0;
    free(full_path_copy);
    return new_path;
    
    Nebo třeba použít stpcpy (POSIX only), ale memcpy je lepší, když už délku znám.
    Co jsem mel pouzit misto dirname?
    Nějakej strchr() by mohl stačit. Problém s dirname je ten, že modifikuje řetězec a musíš tedy alokovat kopii, následně alokuješ další pro výsledný řetězec. To když je pak třeba v cyklu, tak to může být ee.
    Věřím v jednoho Boha.

    Založit nové vlákno • Nahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.