Aussehen
Suche Einloggen
[c] [meta] [fefe] [erp]

/c/ – Eine der letzten echten Webseiten


Antwort erstellen

(≤ 4)



[Zurück]

  • [l] Können wir auf /c/ einen Faden über C haben? Felix Thu, 16 Jul 2026 15:51:07 GMT Nr. 163871
    PNG 387×550 339.8k
    JPG 2048×2030 667.3k
    Hallo, liebes Diät-GPT. Ich traue dir mehr als Google und Co.

    Gibt es inzwischen, im Jahre des Herrn 2026, in irgendeinem aktuellen C-Standard (C23 oder so) eine elegante Lösung für dieses nervige C-Problem?

    #include <stdint.h>
    #include <stdio.h>
    
    #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
    
    void
    c_idiocy(uint8_t arr[4])
    {
    	for (int i = 0; i < ARRAY_LEN(arr); ++i)
     		printf("%u\n", (unsigned)arr[i]);
    }
    
    int
    main(int argc, char *argv[])
    {
    	uint8_t stupid[] = {127, 0, 0, 1};
    	c_idiocy(stupid);
    }
    


    > gcc annoyance.c

    annoyance.c: In function ‘c_idiocy’:
    annoyance.c:4:29: warning: ‘sizeof’ on array function parameter ‘arr’ will return size of ‘uint8_t *’ {aka ‘unsigned char *’} [-Wsizeof-array-argument]
        4 | #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
          |                             ^
    annoyance.c:9:29: note: in expansion of macro ‘ARRAY_LEN’
        9 |         for (int i = 0; i < ARRAY_LEN(arr); ++i)
          |                             ^~~~~~~~~
    annoyance.c:7:18: note: declared here
        7 | c_idiocy(uint8_t arr[4])
          |          ~~~~~~~~^~~~~~
    


    > .a.out

    127
    0
    0
    1
    0
    76
    20
    132
    


    Das ist für Felix echt eine der nervigsten Sachen in C und eng verwandt mit Grundübel von C (Bild 0 relatiert): C kann einfach nicht inzu echte Arrays! (Danke, Dennis!) Selbst nach über 50 Jahren nicht. Es kann nur inzu Pointer; Arrays sind bloß syntaktischer Zucker (vermutlich Blei(II)-acetat).

    Auch nervig und verwandt: Zuweisungen zwischen Arrays sind nicht möglich, selbst wenn sie den gleichen Typ und die gleiche (feste) Größe haben. Du musst jedesmal memcpy() verwenden. Aber packe dein Array in ein Struct, und schwupps auf magische Weise geht es plötzlich: Structs lassen sich anders als Arrays nämlich zuweisen ohne memcpy(), selbst wenn sie wiederum Arrays als Member haben. Es schmerzt.
  • [l] Felix Thu, 16 Jul 2026 15:59:27 GMT Nr. 163873
    Man muss für den ungeübten C-Programmierer – weil es wirklich nicht offensichtlich und vollkommen inkonsistent ist – vielleicht noch erwähnen, dass das hier kein Problem ist:

    #include <stdint.h>
    #include <stdio.h>
    
    #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
    
    int
    main(int argc, char *argv[])
    {
    	uint8_t arr[] = {127, 0, 0, 1};
    
    	for (int i = 0; i < ARRAY_LEN(arr); ++i)
     		printf("%u\n", (unsigned)arr[i]);
    }
    


    Da gibt es keine (berechtigte) Warnung und die Ausgabe entspricht der Intention des Programmierers:

    >
    127
    0
    0
    1
    


    Es wird erst dann – und nur dann – ein Problem, wenn du den Kot in eine externe Funktion auslagern willst (ReFakToRIsiReN).
  • [l] Felix Thu, 16 Jul 2026 21:29:26 GMT Nr. 163884
    PNG 1017×1907 438.8k
    PNG 339×408 177.5k
    JPG 3054×1710 342.2k
    PNG 1085×288 34.8k
    >>163871
    >>163873
    Alt und zerdengelt: In JavaScript primitive Typen in ein Object packen, um Pass-by-Reference zu ermöglichen.
    Neue Heißheit: In C seine Arrays in ein struct packen, um die Array-Länge herausfinden zu können.

    #include <stdint.h>
    #include <stdio.h>
    
    #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
    
    typedef struct IP IP;
    struct IP
    {
    	uint8_t arr[4];
    };
    
    void
    c_idiocy(IP ip)
    {
    	for (int i = 0; i < ARRAY_LEN(ip.arr); ++i)
     		printf("%u\n", (unsigned)ip.arr[i]);
    }
    
    int
    main(int argc, char *argv[])
    {
    	IP stupid = {127, 0, 0, 1};
    	c_idiocy(stupid);
    }


    https://godbolt.org/z/bn8a8Ys7e
  • [l] Felix Thu, 16 Jul 2026 21:46:19 GMT Nr. 163886 SÄGE
    >>163884
    Hups, habe gerade im OP
    >Structs lassen sich anders als Arrays nämlich zuweisen ohne memcpy(), selbst wenn sie wiederum Arrays als Member haben.
    gelesen. Naja, es funktioniert dann eben auch so mit der Array-Länge.
  • [l] Felix Thu, 16 Jul 2026 23:19:50 GMT Nr. 163901
    >>163884
    Gefragt war nach einer eleganten Lösung. Alle Arrays in ein eigenes struct zu packen, nur weil die Sprache/der Compiler behindert sind, ist das Gegenteil von elegant.

    Wo du schon C++ ansprichst: Das Vorgehen erinnert mich an RAII. Was auch nur existiert, weil C++ zwar einerseits Exceptions hat, andererseits aber nur ein try-catch und kein try-finally hat. Das ist so wie jemand, der jeden Tag Steak isst, aber sich weigert, ein Messer zu kaufen, und stattdessen immer die Rückseite der Gabel als Messer verwendet, seit über 30 Jahren, und stur darauf beharrt, das wäre so besser, es wäre ein "Design Pattern", alle müssen das so machen und es muss an den Unis gelehrt werden.

    Arrays in Structs zu packen und sich damit überall nutzlosen Boilerplate-Code einzuhandeln, ist fast genauso beschissen.

    Modernes C hat ja jetzt seit einigen Jahren static in Array-Argumenten:

    void
    c_idiocy(uint8_t arr[static 4])
    {
    	for (int i = 0; i < ARRAY_LEN(arr); ++i)
     		printf("%u\n", (unsigned)arr[i]);
    }
    


    Leider scheint das aber hier nichts zu bewirken und auch sonst hat Felix dafür bisher so wenig Anwendungsfälle gefunden, in denen es nützlich war, dass er schon wieder vergessen hat, was es eigentlich genau macht.

    Aber Felix hatte aber gehofft, dass es inzwischen – im fickenden Jahre 2026 des Herrn – etwas ähnliches vielleicht gibt, das aber funktioniert und nicht scheiße ist. Meinetwegen auch irgendeine proprietäre Compilererweiterung, irgendein Attribut, das von gcc und clang gleichermaßen unterstützt wird, was weiß ich, ich nehme alles.

    Oder eine Syntax wie in den Linux man pages, vgl. Fefe [0]:
    >Liest hier zufällig jemand aus dem C-Standardisierungsprozess mit?
    >
    >Linux-Man-Pages haben neuerdings eine eigene Syntax für Funktionsbeschreibungen. Hier ist ein Beispiel:
    >
    >
    SYNOPSIS
           #include <string.h>
    
           size_t strnlen(size_t maxlen;
                          const char s[maxlen], size_t maxlen);
    

    >
    >Wieso kann das reguläre C das eigentlich nicht?
    >
    >[...]

    Wieso das reguläre C das eigentlich nicht kann, finde ich immer noch eine berechtigte Frage. Als ich diese Notation zum ersten mal in den man Pages auftauchen sah, ging ich tatsächlich davon aus, das sei irgendein neues Feature von C11 oder so sei. Erst durch Fefes Block-Eintrag habe ich gelernt, dass dem leider nicht so ist.)

    [0] http://blog.fefe.de/?ts=96da664d
  • [l] Felix Fri, 17 Jul 2026 15:40:23 GMT Nr. 163916
    JPG 968×968 40.3k
    JPG 700×600 68.9k
    >>163901
    >Gefragt war nach einer eleganten Lösung.
    Aber ja doch! Mit NOGGER_LEN!

    #include <stdint.h>
    #include <stdio.h>
    
    #define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
    #define NOGGER_LEN(x) (sizeof(*x)/sizeof((*x)[0]))
    
    void
    c_idiocy(uint8_t (*arr)[4])
    {
    	for (int i = 0; i < NOGGER_LEN(arr); ++i)
     		printf("%u\n", (unsigned)(*arr)[i]);
    }
    
    int
    main(int argc, char *argv[])
    {
    	uint8_t stupid[] = {127, 0, 0, 1};
    	c_idiocy(&stupid);
    }


    https://godbolt.org/z/Y5W1z3jqa

    Felixens Meinung nach sind Dinge wie
    void f(uint8_t arr[4]);

    auch extremst selten, und stattdessen nimmt man tatsächlich häufig einen benutzerdefinierten Typ (z.B. Vector4 oder Matrix4x4), oder es ist sowieso Teil von einem struct. Dann kriegt man etwas Typprüfung auch frei Haus drübergesprenkelt. Von allen Problemen von C ist das auf Felixens Liste so weit unten, dass Felix das kaum noch wahrnimmt. Da hat Felix doch viel mehr Verlangen nach "ausgewogener Operatorüberladung", wie es GLSL oder HLSL vormachen.
  • [l] Felix Fri, 17 Jul 2026 16:31:45 GMT Nr. 163917
    JPG 255×342 27.8k
    >>163916
    Danke, Diät-GPT. Das ist tatsächlich sogar recht naheliegend und in gewisser Weise Sinn ergebend. Komme mir jetzt etwas blöd vor, dass ich darauf nicht selber gekommen bin.

    >extremst selten, und stattdessen nimmt man tatsächlich häufig einen benutzerdefinierten Typ (z.B. Vector4 oder Matrix4x4),
    Naja, leider tritt dasselbe Problem auch mit einem Typedef immer noch auf. Und dass sowas "extremst" selten ist, würde ich auch nicht sagen, vor allem, wenn man nur mal eben schnell was hacken oder ausprobieren will. Manchmal ist es auch genau das, was man will, und alles, was man drumrumbasteln könnte, wäre nur Bloat.

    >Von allen Problemen von C ist das auf Felixens Liste so weit unten, dass Felix das kaum noch wahrnimmt.
    Dann leg mal los. Schließlich ist dies ein Faden über C.
  • [l] Felix Fri, 17 Jul 2026 21:41:58 GMT Nr. 163933
    >>163917
    >>extremst selten, und stattdessen nimmt man tatsächlich häufig einen benutzerdefinierten Typ (z.B. Vector4 oder Matrix4x4)
    >Naja, leider tritt dasselbe Problem auch mit einem Typedef immer noch auf.
    Felix meinte eher so etwas wie:

    typedef union Vector4 Vector4;
    union __attribute__((aligned(16))) Vector4
    {
        struct
        {
            float x, y, z, w;
        };
    
        float v[4];
    };
    
    typedef union Matrix4x4 Matrix4x4;
    union __attribute__((aligned(16))) Matrix4x4
    {
        struct
        {
            float m11, m12, m13, m14;
            float m21, m22, m23, m24;
            float m31, m32, m33, m34;
            float m41, m42, m43, m44;
        };
        
        float m[4][4];
        float v[16];
        Vector4 row[4];
    };


    Statt so ein float v[4] zu übergeben, übergibt man dann einen Vector4. Allerdings benutzt man dann sowieso kaum ein ARRAY_LEN() auf einem Vector4, sondern hartkotiert einfach 4.

    >Und dass sowas "extremst" selten ist, würde ich auch nicht sagen, vor allem, wenn man nur mal eben schnell was hacken oder ausprobieren will. Manchmal ist es auch genau das, was man will, und alles, was man drumrumbasteln könnte, wäre nur Bloat.
    Bei Felix tritt das zwischen f(int * arr, size_t n) und f(Vector4 v) eigentlich gar nicht auf. Felix kann sich noch nicht einmal daran erinnern, wann er zuletzt ein Array mit statischer Größe an eine Funktion übergeben hätte.

    >Dann leg mal los. Schließlich ist dies ein Faden über C.
    Felix verfolgt bei neuen Sprachfeatures den folgenden Ansatz: Muss man in der Sprache einen Hack machen, um das gewünschte Ergebnis zu erhalten? Dann kann es reif sein für ein eigenes Feature.

    *Felix benutzt Präfixe für Funktionsnamen/für structs in seiner C-Kotbasis. Da wären namespaces gut, aber nicht so, wie in C++. Soll heißen: Man muss vor einer #include-Direktive den Namen eines Namespace, der dann in der inkludierten Datei folgen wird, zuvor umbenennen können.
    *Felix benutzt Suffixe für Funktionsnamen. Da wäre Funktionsüberladung gut.
    *Felix benutzt wilde Makro-Geschichten um von einigen structs mehrere Varianten zu erhalten, welche dann auch noch ihren eigenen Suffix erhalten. Ein bisschen Generics.
    *Felix benutzt schon mal etwas Mathe und das wird teilweise schlecht lesbar. Da wäre Operatorüberladung wie in GLSL oder HLSL gut. Gibts aktuell natürlich nur für complex in C.
  • [l] Felix Fri, 17 Jul 2026 21:59:32 GMT Nr. 163934
    PNG 500×390 266.8k
    >>163933
    >Allerdings benutzt man dann sowieso kaum ein ARRAY_LEN() auf einem Vector4, sondern hartkotiert einfach 4.
    Mein Professor hat aber gesagt, unbenannte Konstanten im Kot sind haram!

    >Muss man in der Sprache einen Hack machen, um das gewünschte Ergebnis zu erhalten? Dann kann es reif sein für ein eigenes Feature.
    >[...]
    >*Felix benutzt Suffixe für Funktionsnamen. Da wäre Funktionsüberladung gut.
    Gute Neuigkeiten! C11 hat da einen Hack für! _Generic

    >*Felix benutzt wilde Makro-Geschichten um von einigen structs mehrere Varianten zu erhalten, welche dann auch noch ihren eigenen Suffix erhalten. Ein bisschen Generics.
    Vielleicht auch dafür geeignet.

    >*Felix benutzt schon mal etwas Mathe und das wird teilweise schlecht lesbar. Da wäre Operatorüberladung wie in GLSL oder HLSL gut. Gibts aktuell natürlich nur für complex in C.
    Mein ProfessorYouTube-Programmier-Guru hat aber gesagt, das ist verborgener Kontrollfluss und deshalb haram! Außerdem sind Infix-Notation und Operatorpräzedenzregeln doch sowieso Bloat. Nicht minimalistisch genug. Besser LISP oder Forth nehm

    >Da wären namespaces gut, aber nicht so, wie in C++. Soll heißen: Man muss vor einer #include-Direktive den Namen eines Namespace, der dann in der inkludierten Datei folgen wird, zuvor umbenennen können.
    Bist du sicher, dass du nicht vielleicht bei Python und NumPy besser aufgehoben wärst? :3
  • [l] Felix Sat, 18 Jul 2026 07:07:59 GMT Nr. 163937
    Ach, ist das süss die Diskussion hier - und nur, weil hier scheinbar niemand verstanden hat, wie Arrays in C gedacht sind:
    - Arrays starten bei 1.
    - Array[0] wird mit der Arraylänge beschrieben.
    Das war schon immer so und wird auch immer so bleiben. Nur irgendwelche Mongokinder, die sich C selbst beigebracht haben, verstehen das nicht und haben deshalb die Probleme wie hier im Faden zu sehen. Seht es einfach ein: Arrays starten bei 1, und in Position 0 wird die Arraylänge geschrieben!
  • [l] Felix Sat, 18 Jul 2026 07:27:00 GMT Nr. 163939 SÄGE
    >>163937
    Nicht du schon wieder.
  • [l] Felix Sat, 18 Jul 2026 13:29:15 GMT Nr. 163948
    >>163871
    >bloß syntaktischer Zucker (vermutlich Blei(II)-acetat).
    *munzelte*
  • [l] Felix Sat, 18 Jul 2026 17:09:32 GMT Nr. 163952
    >>163939
    Doch, ich schon wieder! Statt rumzujammern beweise mir doch mal, warum es nicht offensichtlich überlegen ist, Arrays bei 1 starten zu lassen und die Position [0] für die Länge zu verwenden! Ach halt, wenn du schlagende Argumente hättest, hättest du diese gebracht statt inhaltslos rumzunölen! *ZWINKERSMILEY*
  • [l] Felix Sun, 19 Jul 2026 00:57:42 GMT Nr. 163963
    *bing*
  • [l] Felix Mon, 20 Jul 2026 07:04:14 GMT Nr. 163971
    juhu, das Sertikack wurde erneuert, Lang lebe Dietchan!
  • [l] Felix Mon, 20 Jul 2026 20:01:17 GMT Nr. 163973
    >>163952
    Du kannst nicht einfach Slices deines Arrays übergeben. Musst dafür jedesmal eine Kopie erstellen. Voll umständlich und dumm. Außerdem bist du eh nur ein dummer Troll ¯\_(ツ)_/¯
  • [l] Felix Tue, 21 Jul 2026 05:30:37 GMT Nr. 163974
    >>163973
    Warum solltest du nur Scheiben deines Reihe übergeben? Du übergibst das ganze Reihe, und nutzt in deinen Funktionen natürlich die Logik, dass du die 0. Position für die Länge nimmst und entsprechend in Schleifen und co. überspringst. Es ist wirklich ganz einfach, wenn man es mal angefangen hat. Das Problem sind nur so Frickel-Nerds, die keine Ahnung von C haben und entsprechend Kot kotieren, der damit nicht umgehen kann, und dann der Meinung sind, ihren schlecht programmierten Rotz in die Welt zu giessen.
  • [l] Felix Tue, 21 Jul 2026 11:13:28 GMT Nr. 163976
    JPG 2970×2288 560.2k
    >>163974
    >Warum Slices
    >Du übergibst den ganzen String
    Und wenn man einen Substring übergeben will, muss man dann den ganzen String + eine Range (Index für Anfang, Index für Ende + 1) übergeben, weil man für das simple Erstellen eines Substrings nichts neu allozieren will. Und weil jede Funktion für Strings auch für Substrings (sind schließlich ebenfalls Strings) funktionieren soll, muss damit jede Funktion einen String + eine Range übergeben kriegen. Und damit kann man dann das Speichern der Länge sich auch komplett sparen, denn die Info steckt bereits in der Range (welche für den ganzen String dann die Indizes (0, n) hat).

    Und wenn man sowieso einen Daten-Pointer im String hat, dann kann man den ersten Index der Range auch dort einfach reinfalten, und statt { char * data; uint32_t start; uint32_t end } schlicht { char * begin, uint32_t length } speichern. Und dabei sollte natürlich data/begin non-owning sein, und man sollte seine Strings durch einen Allokator anderswo allozieren lassen, denn dadurch kriegt man das Problem weg, dass erstens beim Zerstören von Slices man irgendwie die Startadresse des Strings wieder erhalten muss, um diese Adresse an free()/delete zu übergeben, und dass zweitens damit nach dem Deallozieren eines Slices auch dann alle anderen Slices ungültig werden würden und der ursprüngliche String ungültig werden würde, was man ebenfalls nicht will. Man will es daher wegen der ggf. existierenden Slices tatsächlich non-owning haben. Und damit ist man nur durch logisches Schließen bei einer string_view herausgekommen.

    Allokator für Speicher + string_view + StringBuilder ist eben die Traumkombination, die sich für Strings herauskristallisiert hat.
  • [l] Felix Tue, 21 Jul 2026 17:28:00 GMT Nr. 163977
    >>163976
    Lern inzu Zeiger!
  • [l] Felix Tue, 21 Jul 2026 19:20:55 GMT Nr. 163980
    PNG 417×397 106.4k
    JPG 3024×4032 3.0M
    >>163977
    Weil eine string_view auch gar keine Zeiger enthält...

    Es ist sogar die zeigerigere Variante. Denn was passiert, wenn der zugrundeliegende zugehörige Speicher des Strings verschoben wird (z.B. weil etwas drankonkateniert wird)? Genau, die string_view zeigt auf Müll.

    Deswegen tendieren einige dazu, Strings generell nicht erweiterbar zu machen, und für Konkatenierungen den StringBuilder zu bemühen, der dann einen neuen String bauen kann. Wenn viel konkateniert wird, kriegt der String seine eigene Arena (bei der man reservierten virtuellem Speicher hat, der Stück-für-Stück weiter committiert werden kann).
  • [l] Felix Wed, 22 Jul 2026 17:13:06 GMT Nr. 163983
    >>163980
    Mach das doch nicht so kompliziert! Es ginge ganz einfach. Ein Array, ein Pointer, eine Länge, und nur mit Pointer und Länge kannst du jeden beliebigen String aus dem Array ziehen. Du brauchst nur das Array zunächst mit unendlicher Länge zu definieren und komplett mit Zufall zu definieren, dann noch eine Suchfunktion, die deinen Wunschstring in dem Array sucht, und schon hast du alles, was du brauchst! Und wenn du zwei Strings concatieren willst, dann suchst du einfach den zusammengesetzten String im Array. Einfacher geht das nun wirklich nicht!
  • [l] Felix Wed, 22 Jul 2026 17:53:30 GMT Nr. 163984
    >>163983
    >Mach das doch nicht so kompliziert! Es ginge ganz einfach. Ein Array, ein Pointer, eine Länge, und nur mit Pointer und Länge kannst du jeden beliebigen String aus dem Array ziehen.
    Bis dahin war es unironisch das, was ich vorgeschlagen hatte.

    >Du brauchst nur das Array zunächst mit unendlicher Länge zu definieren und komplett mit Zufall zu definieren
    Dort entgleiste der Pfosten dann...

    >dann noch eine Suchfunktion, die deinen Wunschstring in dem Array sucht, und schon hast du alles, was du brauchst! Und wenn du zwei Strings concatieren willst, dann suchst du einfach den zusammengesetzten String im Array. Einfacher geht das nun wirklich nicht!
    ...und kam bei den tausend Affen mit den tausend Schreibmaschinen raus.
  • [l] Felix Wed, 29 Jul 2026 08:01:04 GMT Nr. 164107
    *Uppercut*
    Nur damit der C-Faden wieder auf /top ist
  • [l] Felix Wed, 29 Jul 2026 11:03:39 GMT Nr. 164112
    >>163983
    >Du brauchst nur das Array zunächst mit unendlicher Länge zu definieren und komplett mit Zufall zu definieren, dann noch eine Suchfunktion, die deinen Wunschstring in dem Array sucht, und schon hast du alles, was du brauchst!
    Die beste Idee seit πfs InferenceFS

    <This file doesn't look like what I remember.
    <Are you sure? It's been a while since you last opened it. Memory is funny like that. The file is fine — maybe take another look with fresh eyes.
  • [l] Felix Sat, 22 Aug 2026 18:09:55 GMT Nr. 164635
    K&R C ergibt LSD, wenn man die Buchstaben um eins verschiebt. Wer wusste es? Wieder keiner.


[Zurück]
[c] [meta] [fefe] [erp]