C/C++

C++ #include ram probléma [MEGOLDVA]

Fórumok

https://github.com/earlephilhower/ESP8266Audio könyvtárat szeretném használni, de ez bootoláskor dől el hogy tényleg kell-e.

Ha csak #include "AudioFileSourceSPIFFS.h" van a kódban, semmi más, akkor is megeszik vagy 10kb ramot. Átnéztem de nem találom a bűnöst.

Egy extern boolt szeretnék beletenni, ha az false, felejtse el az egész projektet, de arra se jövök rá hogy hova tűnik a ram.

THX!

[Megoldva] Nem blokkolós I/O

Fórumok

Van nekem Linuxon egy /dev/ttyACM0 karakter eszközfile-om (USB CDC). Szeretném olvasni, de nem blokkolósan. Tehát azt szeretném, hogy a karakter olvasása ne akkor térjen vissza hozzám, ha van olvasható karakter, hanem akkor is, ha nincs, s akkor tudjam, hogy az nincs. Ennélfogva tudjak rá timeout-ot csinálni.

Próbáltam így:

c = fgetc_unlocked(dfd);

Ez vagy nem az, ami nekem kell, vagy nem tudom, hogyan kell használni, de ez is megvárja alapesetben, amíg jön egy karakter. Hogyan kell ezt csinálni? Mi kell nekem? poll(), epoll(), select()? Esetleg 

fcntl(fileno(dfd), F_SETFL, O_NONBLOCK);

vagy mi a megoldás?

A megoldás a poll() és read() használata lett.
 

[Megoldva] warning: Unsequenced modification and access to 'j'

Fórumok

Na, de miért?

while (isupper((unsigned char) p[j])) buff[j++] = p[j];

Az '=' operátor right to left asszociatív. Vagy dönthet a fordító úgy, hogy a magasabb precedenciájú kifejezéseket akármilyen sorrendben értékelteti ki futásidőben, s majd a részeredmények felhasználásával lesz az értékadás jobbról balra? Mert én úgy gondoltam, amikor ezt a sort leírtam, hogy előbb meghatározza p[j] értékét, majd utána ezt értékül adja buff[j]-nek, majd j-t növeli eggyel.

Ezt a warningot egyébként a Qt Creator zúdítja rám. Miért nem mcedit-tel írom a forráskódot? Akkor boldog tudatlanságban élhetnék... :)

Megoldásnak gondoltam korábban. Illetve megkerestem szemmelveréssel - eltartott egy darabig, amíg végignéztem a

grep -anF '++' *.[ch] | less

eredményeit. Egyetlen helyen használtam ezt a csúnya megoldást. Kijavítottam. Már úgy értem, abban a kódban, amelyikben szólt a Qt Creator mögött lévő analizátor, a nyitóban idézett volt az egyetlen ilyen, de van egy sokkal fontosabb kód, amiből termék lesz, abban nem szeretnék bugot. Abban volt egy ilyen csúnyaság.

Jobban megoldás. :)
 

QOI 2.0

Fórumok

Egy kis újabb csemege a bitpornó kedvelőinek :-)

Nem tudom, hányan ismeritek a Quite OK Image képformátumot. A lényege, hogy eszeveszettül faék egyszerű, mégis egész jó tömörítési rátát képes produkálni (a honlapja mondjuk hazudik, speciálisan kézzel összeválogatott képen demózza). Viszont volt benne pár dolog, ami mindig is zavart (például hogy nem képes transzparens képeket tömöríteni), ezért feltúrbóztam kicsit:

QOI 2.0

Fícsörök:
- ugyanúgy egyetlen függőség nélküli fejlécfájl, mint az elődje (kb. 200 SLoC a kicsomagoló-becsomagoló együtt)
- ugyanúgy MIT licenszű, Szabad és Nyílt Forráskódú
- azonban ez sokkal gyorsabb, pláne nagy képek esetén
- ráadásul sokkal jobban tömörít (különösen anti-aliasolt képeket)

A sebességnövekedés amiatt van, hogy mutatókat és switch/case-t használ bájttömbindexek és if/else blokkok helyett, egyébként ugyanaz a logika, nincs benne semmi trükk. A jobb tömörítési rátát pedig úgy éri el, hogy okosabban osztja ki a biteket, a legtöbb utasítás ugyanaz, de a futásidejű tömörítésre van egy hosszabb futamot is tárolni képes opció, a differencál utasításoknál van egy olyan, ami alfát és nagyobb tartományt képes leírni, a teljes csatornát tároló utasítás pedig csak a megváltozott csatornákat tárolja az összes helyett. Röviden.

Beágyazott WebAssembly futtatása

Fórumok

Tegyük fel, hogy felmerül az igény a ~-ra, azaz hogy egy programból kell tudnunk hívni WASM eljárásokat, és vice-versa, azoknak is kell hívniuk a mi natív függvényeinket. Na erre nem találtam épkézláb megoldást.
- Az egyik ilyen a wasm-micro-runtime, de hogy ez mennyire szar, azt semmi sem szemlélteni jobban, minthogy félezer fájl, 9 MEGA az nekik "micro"... Hát nekem hányadék bloatware.
- Ott volt aztán még a wasm3, ami méretét tekintve már inkább elfogadható, viszont agyfasz az API-ja, és sajnos nincs már karbantartva, mert a fejlesztőjének a házát szarrábombázták a ruszkik.
- Van még a Linux kernelbe ágyazható cervus, szintén elhalt, 7 éve bottal sem piszkálták, pedig nyitott jegyek vannak rajta.
- ...stb.

És akkor ott van még az is, hogy ezek egyike sem biztonságos, mert ezekkel BÁRMILYEN dll / so dinamikusan betölthető és futtatható, így a beágyazó programnak esélye sincs kordában tartani a benne futó szkriptet. Szóval nem az igazi.

Egy szónak is száz a vége, már megint az lett, hogy megírtam a libet magamnak, mert amit mindenki más használ, az nekem nem tetszik. Hát, ez van.

https://gitlab.com/bztsrc/wa

Előnyei:
- ha az első a micro, na akkor ez nano, merthogy 9.5 Mega helyett csak 116 Kilobájt az egész (kb. 1900 SLoC)
- mégis megvalósítja a teljes WASM MVP (Minimal Viable Product) szabványt
- egyetlen függőségmentes ANSI C / C++ fejlécfájl (na jó, libm kell neki, de a WA_NOLIBM define kikapcsol két utasítást és úgy már tényleg csak compiler built-inek elegek)
- pofonegyszerűen használható, faék egyszerű az API-ja
- maximális kontroll afelett, hogy mit csinálhatnak a szkriptek (mennyi memóriát foglalhatnak, milyen függvényeket hívhatnak stb.)
- bound check és hasonló nyalánságok (futás idejű típusellenőrzésen kívül szinte minden)
- baromi gyors, a többihez képest lobog a hajad tőle (két okból: bulk memóriafoglalás kev;s bufferre; és az értelmetlen típusellenőrzés helyett (ami O(N)) csak az elemszámot ellenőrzni (ami O(1))
- a többi megoldás memóriaigényének 10%-val is beéri (nem, nem írtam el, ugyanazt a wasm modult futtatni tized annyi memóriát fogyaszt)
- a többivel ellentétben memleak mentes (ez ráadásul garantált, mivel nem foglalgat agyba-főbe kis memóriablokkokat, hanem mindössze egy fél maréknyi buffert használ)
- nem támogat semmiféle emscripten, WASI meg hasonló 3rd party baromságot, így a szkript nem tud kitörni a sandboxából. Nincs mivel.
- fordítható debugger támogatással, példa wadbg debugger GUI applikáció is van hozzá, ennek demonstrálására (kicsi SDL-es, portolható cucc).

Példa használatra:

/* függvénykönyvtár behúzása, stb módra, nem kell linkelni semmivel */
#define WA_IMPLEMENTATION
#include "wa.h"

/* wasm bináris bitkolbásza, fordította "Clang --target=wasm32", yours truly */
uint8_t wasmbinary[1234] = { ... };

/* futás idejű linkelő tábla és kontextus */
RTLink link[] = {
    /* név       ki       be  proto */
    { "malloc",  &malloc,  0, WA_ll },  /* host -> WASM */
    { "realloc", &realloc, 0, WA_lll }, /* host -> WASM */
    { "free",    &free,    0, WA_vl },  /* host -> WASM */
    { "add",     NULL,    -1, WA_fff }, /* WASM -> host */
    { "sub",     NULL,    -1, WA_fff }, /* WASM -> host */
    { "globvar", &globvar, 0, WA_i },   /* megosztott változó */
    { 0 }
};
Module m;

/* betöltés, inicializálás */
wa_init(&m, wasmbinary, 1234, link);

/* egy WASM függvény hívása C-ből. Elöször kikeressük a szimbólumot (ha nem felejtettük el,
   hogy a link[] tömb hányadik sora, akkor keresgélés helyett csak simán O(1) lekérés) */
int addfunc = cavinton_klub? wa_sym(&m, "add") : link[3].fidx;

/* bemeneti paraméterek átadása és hívás */
wa_push_f32(&m, 1.0);
wa_push_f32(&m, 2.0);
ret = wa_call(&m, addfunc);
printf("Eztetet adta vissza: %f\n", ret.f32);

/* többet nincs mit elmondani, kérem kapcsoljaki */
wa_free(&m);

Ennyi. Ennél faékebb egyszerűségű és könnyebben integráható API-t nem bírtam kiagyalni. Négy függvény init / push / call / free és kész (oké, a push-ból van több változat, mindenféle típushoz, de akkor is 12 függvény cakk-um-pakk). A valós idejű linkelés meg egy struct tömbbel zajlik, aminek négy mezője van:
- első a szimbólum (UTF-8 sztring)
- második egy memóriacím, ezt te adod meg akkor, ha a WASM-nek akarod átadni
- harmadik egy függvényindex, ezeket meg a WASM adja meg, hogy meg tudd hívni
- negyedik meg egy prototípust kódoló bitmaszk

Bármelyik globális WASM változó láthatóvá tehető host oldalon, ha felvesszük a táblába a WASM szimbólum nevét egy host memóriacímmel. Másik irány is működik, ekkor "extern"-nek kell definiálni a WASM modulban.

De ami biztonság szempontjából nagyon fontos, a WASM szkript nem tud semmi mást meghívni, csak azokat, amik szerepelnek a listán.
Viszont ott bármilyen függvénnyel működik, de azért lehetőség van saját dispatcher megadására is egy WA_DISPATCH define-nal.

Szabad és Nyílt Forráskódú, licensze a megengedő MIT.

ld: warning: main.elf has a LOAD segment with RWX permissions

Fórumok

Egy FPGA-s projekt kapcsan futottam bele a fenti uzenetbe. A kontextus: sima C kod forditasa beagyazott kornyezetben. A limitaciok miatt a teljes zubehor, init-estul, text-estul, rodata+data+bss-estul egyetlen RAM blokkba kerul, onnan is fut, azaz nem kulonul el a "flash" es a "ram" mint a szokasos esetekben - es emiatt kapom a targybeli hibauzenetet linkeleskor. Ez igy nyilvan rendben is van, de mivel ez tudatos, szeretnek megszabadulni ettol a figyelmeztetestol. Az interwebeken azt irjak hogy az .init meg a .text (READONLY) attributuma ezt megoldja, de sajna ez nem segit. Egyeb otlet? :) 

A rendszer egyebkent RISC-V + picolibc alapu, igy a hozza tartozo alap linker szkriptet (/usr/lib/picolibc/riscv64-unknown-elf/lib/picolibc.ld) modositottam egy kicsit hogy minden egy RAM blokkba keruljon. De egy kicsit el is vesztam az ilyen .text { ... } >ram AT>ram :text meg hasonlo nyalanksagokban is... 

Thx, A.

[Megoldva] Kioptimalizálódhat-e a függvényhívás?

Fórumok

Nézzük az alábbit:

#define INTERRUPT_test_and_run(PIE, PIR, MASK, FNC) (((PIE) & (PIR) & (MASK)) ?\
                                                        (FNC, true) : false)

void __interrupt() INTERRUPT_InterruptManager(void) {

    bool ready;

    ready = false;
    ready |= INTERRUPT_test_and_run(PIE3, PIR3, _PIR3_TMR0IF_MASK, tmr0_isr());
    ready |= INTERRUPT_test_and_run(PIE4, PIR4, _PIR4_U1RXIF_MASK, rx_isr());
    ready |= INTERRUPT_test_and_run(PIE4, PIR4, _PIR4_U1TXIF_MASK, tx_isr());
    if (!ready) RESET();                                                        // unhandled interrupt
}

Gondolhatja-e a fordító, hogy a RESET() hívásához szükséges ready változó helyes előállításához szükségtelen a makróban hivatkozott FNC meghívása? Mert ha ezt gondolja, akkor épp az interrupt handlert fogja kispórolni, és sovány vigasz lesz annak a néhány byte-nak a megspórolása. :) Veszélyes-e ebből a szempontból ez a makró?

Szerk.: Nem azt állítom, hogy most rosszul fordítja - még nem próbáltam ki -, hanem az a kérdés, hogy vajon ez egy annyira ügyetlen makró, amitől állandóan ott a fejem felett a pallos, hogy egyszer csak kispórolja a fordító az IT handler hívását, vagy ez így teljesen jó, netán teljesen rossz, vagy picit módosítani kellene rajta?

Megjegyzés:

Annak, aki esetleg érdekesnek gondolja, úgy tűnik, az eredeti makró - itt fentebb - hibás, s a fordító nem érzi szükségesnek a vessző operátor előtti függvény hívását, hiszen a kifejezés anélkül is kiértékelhető. Akkor viszont nem hívódik az interrupt handler.

[MEGOLDVA] Linux waitpid pipe-pal

Fórumok

Ez már kezd az agyamra menni... Hogy kell lekérni Linux alatt a child visszatérési értékét, ha pipe is van? Rohadtul nem úgy működik, ahogy a man page állítja!

Pipe (és WNOHANG) nélkül minden okés:

    ret = 0;
    if(!(pid = fork())) {
        ret = 1;
        printf("child ret %d\n", ret);
        exit(ret);
    } else
    if(pid > 0) {
        waitpid(pid, &ret, 0);
        printf("parent ret %d\n", ret);
    }

Kimenet:

child ret 1
parent ret 1

Na de nekem az kellene, hogy a gyerek futtasson le egy parancsot, ha nem sikerül, akkor írja ki a hibát, és mindezt a szülő pipe-al olvassa, ugyanakkor a visszatérési érték is kéne, hogy sikerült-e a futtatás.

Teljes példa:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char **argv)
{
    char output[4096];
    int stdoutpipe[2], l, ret = 0;
    pid_t pid;

    if(pipe(stdoutpipe) < 0) { fprintf(stderr, "unable to create pipe?\n"); return 1; }
    if(!(pid = fork())) {
        close(1);
        close(2);
        close(stdoutpipe[0]);
        dup2(stdoutpipe[1], 1);
        dup2(stdoutpipe[1], 2);
        close(stdoutpipe[1]);
#ifdef NOTOKAY
        ret = system("echosaaa");
#else
        ret = system("echo");
#endif
        if(errno) perror(NULL);
        printf("child ret %d\n", ret);
        exit(ret);
    }
    if(pid > 0) {
        close(stdoutpipe[1]);
        do {
            if((l = read(stdoutpipe[0], output, 4096)) > 0)
                write(1, output, l);
        } while(waitpid(pid, &ret, WNOHANG) != pid);
        close(stdoutpipe[0]);
    } else {
        fprintf(stderr, "unable to fork?\n");
        close(stdoutpipe[0]);
        close(stdoutpipe[1]);
    }
    printf("parent ret %d exit %d\n", ret, WEXITSTATUS(ret));

    (void)argc; (void)argv;
    return 0;
}

Ez konstans 0-át ad vissza, akármi is a gyerek exit() paramétere.

$ gcc aaa.c -o aaa; ./aaa

child ret 0
parent ret 0 exit 0

$ gcc -DNOTOKAY aaa.c -o aaa; ./aaa
sh: line 1: echoaaa: command not found
child ret 32512
parent ret 0 exit 0

Magyarán a waitpid NEM állítja a státuszt, akkor sem, amikor a gyerek pidjével tér vissza, holott a man page szerint kéne neki. Példától függően vagy konstans -1, vagy konstans 0 lesz minden exit() értékre a ret.

WTF? Miért nem adja vissza a gyerek státuszát a watpid, ha WNOHANG opcióval hívódott?

És ha ez normális, akkor hogy a francba kell lekérni a gyerek státuszát, ha olvasni is akarja az ember a kimenetét??? Alaposan átolvastam a man page-eket, nagyon nem így kéne működnie! Rengeteg példát is áttúrtam, de bakker, azok vagy csak a visszatérési értéket kérik le, vagy a kimenetet, de egyik sem mindkettőt!

Ami leírást meg github-ot találtam, ott mindenhol azt írják, így működnie kéne. De mégsem működik! Arról sehol nem szól fáma, hogy a waitpid hibás értéket adna vissza a status paraméterben.

Stackoverflow-val sem kerültem közelebb a megoldáshoz, ezt találtam, ami hasonló (neki is a waitpid()-el van baja, ha WNOHANG meg van adva, mondjuk ő 0-át kap vissza), habár ez epoll-al is meg van spékelve. A megoldási javaslat: "One possible implementation is to repeat waitpid(..., WNOHANG) until it returns the expected PID", na de hát én pont eleve ezt csinálom! Akkor WTF?

Boost lib linkelesi hiba [a peldakod mar fordul]

Fórumok

Sziasztok,

Nem hasznaltam meg a Boost library-t, es igazabol csak egy projektet szeretnek leforditani ami hasznal, de amikor linkelnem ossze az object file-okat, tele van "undefined reference"-szel (a Boost:Log kellene vegulis csak).

Felturtam a Google-t, de nem adott relevans talalatokat.

Gondoltam, megkerdezem a ChatGPT-t:

https://chatgpt.com/share/673b3d2d-6674-8013-aa59-eef5c3692b17

Keszitett is egy forrast, illetve, hogy hogyan kellene forditani / linkelni, csak sajnos ugyanugy nem mukodik. A forditas / linkeles eredmenye:

https://pastebin.com/ah9ZRJ9z

Mar probaltam kulon forditani aztan linkelni, mindenfele kapcsolokat (pl. -std=c++11 / -std=c++14 / -std=c++17, -DBOOST_LOG_DYN_LINK, ...), de nem jutok elorebb.

Debian 12, GCC 12.2, a Boost library-k elvileg fent vannak (a -dev csomagok is termeszetesen).

 

Valaki tudja, hogyan lehetne mukodokepesse tenni?

 

Koszi

 

Edit:

A fenti kod mar lefordul.

g++  boost.o -lpthread -lboost_log -lboost_log_setup -lboost_thread -o boost

Sajnos amit szeretnek, az me'g nem. Felmerult bennem, hogy amiatt nem megy, hogy C es C++ is van benne.

Egyebken amit el szeretnek erni, hogy ebbol:

https://github.com/SiliconLabs/UnifySDK

le tudjam forditani ezt:

https://github.com/SiliconLabs/UnifySDK/blob/main/applications/zpc/appl…