Arenas, strings and Scuffed Templates in C

Поділитися
Вставка
  • Опубліковано 10 чер 2024
  • A video made to highlight some strategies and tips for making using C easier
    Discord: / discord
    Relevant Links:
    Arenas:
    www.rfleury.com/p/untangling-...
    www.gingerbill.org/article/20...
    Base Layer Series: / @mr4thprogramming
    My Data Structure Implementations:
    (Completely standalone if you remove the stabletable section)
    github.com/PixelRifts/c-codeb...
    Metaprogramming article by ryan fleury:
    www.rfleury.com/p/table-drive...
    #MadeWithMotionCanvas

КОМЕНТАРІ • 197

  • @WarrenMarshallBiz
    @WarrenMarshallBiz Рік тому +223

    Some days, I just don't feel like writing code. Then a video like this pops up in my feed and I find myself back at the keyboard, refactoring something. Haha ... thanks for the C content!

    • @illegalsmirf
      @illegalsmirf 8 місяців тому

      Most days I don't feel like writing any code. It's boring and unnecessary

    • @zyriab5797
      @zyriab5797 5 місяців тому +3

      @@illegalsmirf Gotta take a break, sounds like burnout, brother.

    • @luay_kelani
      @luay_kelani 4 місяці тому

      Comment of the day after watching tons of videos. This is so real 👏👏

  • @yogxoth1959
    @yogxoth1959 Рік тому +20

    This is the second time that you’re making a video about exactly the same thing I’m working on. Thanks again for the videos, super helpful!

  • @garklein8089
    @garklein8089 Рік тому +45

    Great video!
    For me, the fact that you need to make everything yourself in C is fun : )

    • @hbobenicio
      @hbobenicio Рік тому +11

      I think this is exactly why C is one of my favorite languages. Reinventing some stuff keeps my mind active and sane when diving into languages with lots of abstractions. I think this makes me much more aware about performance trade-off's hidden in language or library goodies.

    • @redcrafterlppa303
      @redcrafterlppa303 Рік тому +3

      ​@@hbobenicio doing the same thing in very high level languages like Java is also pretty fun. It's thrilling using the cracks in the system to poke with a stick into the inner workings of an overcomplicated machine.
      Also bringing Java code to segfault is really entertaining 😂

  • @nikolajolanderrasmussen9128
    @nikolajolanderrasmussen9128 5 місяців тому +6

    Lovely video. Your points completely explain why I switched to zig for nearly all of my performance critical code.

  • @danieljulian4676
    @danieljulian4676 Рік тому +59

    I don't write C any more (and never did any heavy lifting with it), but it's nice to see how development is evolving. I've always liked how much space C gives us to do things our own way (including how to screw things up royally, but I don't see the latter happening here!) I'll definitely give this another view. I'm in awe of the folks who really know how to do this stuff. C is still my favorite language; I never learned to hate it, even though I've had my share of awful bugs just like everyone else, but not as awful as the ones we get when we really know how to code. Now we've learned all about robustness. Cheers!

    • @BboyKeny
      @BboyKeny Рік тому

      What do you write in nowadays?

    • @danieljulian4676
      @danieljulian4676 Рік тому

      @@BboyKeny Whatever gets it done fastest, and that tends to be Python. I'm not working on computationally large problems these days. There's a soft spot in my heart for SML (or maybe it's a soft spot in my head!) I wish I had time to learn something about Haskell, but life is short.

    • @ThienNguyen-bg1kx
      @ThienNguyen-bg1kx 7 місяців тому +2

      If you like C and want to get thing done fast like python, maybe give Go a try?

  • @VictorRodriguez-zp2do
    @VictorRodriguez-zp2do Рік тому +15

    I have done, templates in C using macros. It's not pretty. Some of the reasons why are: confusing error messages, the fact that your code linter will have trouble telling you were errors are, junp to function definition will likely be broken, your code will be less readable, confusing formatting. That was the reason i ultimately switched to D.

  • @kolemannix8256
    @kolemannix8256 4 дні тому

    Fantastic video! Great work

  • @dimitrilesnoff468
    @dimitrilesnoff468 Рік тому +6

    Thank you! I am a CS PhD student and I definitely learned something new: arenas/bump allocator with this video.
    Arenas feel pretty useful to correctly free memory when raising exceptions during the function lifespan. We do not need to remember all the stuff we have to free when quitting the function early on.
    I like to code in the Nim language, for its templates and meta programming features which are well easier to debug (and much more powerful).
    There are plenty of features that I wish were there in C (default values, some automatic type inference for function callbacks, etc...) but the amount of optimisations in Clang/GCC, the reliability of debugging tools like Valgrind, the structural typing and the simplicity of the language (no absurd edge cases to learn like in JS) makes it an incredible language ;)

    • @pyrus2814
      @pyrus2814 5 місяців тому +5

      No offense: how did you get into a CS PhD program without ever having heard about arenas? What exactly are they teaching in schools? :/

  • @kellybmackenzie
    @kellybmackenzie Рік тому

    Thank you SO MUCH, this is amazing and so helpful!! Arenas in special feel genuinely life-changing to learn about, thank you so much

  • @mie5953
    @mie5953 Рік тому +1

    This video explains the ideas very clearly, thanks

  • @Pabloparsil
    @Pabloparsil 7 годин тому

    One metaprogramming option that I'm exploring is using python to generate the C code, and add that C code as a target to a makefile (so that every time I modify the python script, the C files get regenerated). Another option would be to use SCons as a build system, since it's already Python code it would integrate more seamlessly

  • @vinugb
    @vinugb 2 місяці тому

    Great video mate, videos like these keep my spark up, thanks for this ❤

  • @segsfault
    @segsfault 7 місяців тому

    Really nice video! Got This In My Recommendation.

  • @brecoldyls
    @brecoldyls Рік тому +17

    Nice concise explanation of bump arena allocators.
    I have a feeling you like Zig haha.
    Also the explanation of how to use the pre processor to make templates is good.
    I just wish there were a way to do that without using the pre processor or meta programming, but oh well

    • @voxelrifts
      @voxelrifts  Рік тому +11

      Haven't used zig at all actually! But have heard good stuff about it

    • @Yadobler
      @Yadobler 19 днів тому +1

      ​@@voxelrifts same thing popped in my mind, sounds like how zig handles memory allocation, and meta programming can be done in the same sourcefile with a comptime keyword

  • @user-hk3ej4hk7m
    @user-hk3ej4hk7m Рік тому +19

    The lack of templates is really what's dragging c down, and it's the main reason I use c++, only for the templates though, not for the OOP stuff. Great video! Arena allocators are wonderful.

    • @xr.spedtech
      @xr.spedtech Рік тому +2

      C21 has a maxro to aid with that ...
      I have 30 K total so far, templates are not good for C that is just your personal preference.

    • @user-hk3ej4hk7m
      @user-hk3ej4hk7m 11 місяців тому +1

      Yeah I'd much rather void* everything

    • @captainfordo1
      @captainfordo1 11 місяців тому +4

      I'm very glad that C doesn't have templates. They make debugging a mess, and are generally not fun to use in my experience.

    • @user-hk3ej4hk7m
      @user-hk3ej4hk7m 11 місяців тому +6

      @@captainfordo1 It's a compromise between static correctness and runtime correctness. Templates avoid type erasure with void*, which leads to needing to use the debugger more often, if you're lucky to find the error before you segfault. It's been proven time and time again that generics are the way to go (literally, even go has them), without generics you'll spend time reinventing the wheel or dealing with type erasure. I meant C having "templates" as a way to do generics, not specifically to have the same implementation as in C++, which is what you're saying is hard to debug.
      Also it is not clear if you meant hard to debug as in "the compiler error messages when using templates are hard to understand", or if you literally mean debug template code, which are very different things. If you can't understand compiler errors then ask chatgpt, it's great help, better than having no compiler errors but a few bugs.

  • @ailijic
    @ailijic Рік тому

    Great video, you have my subscription.

  • @starc0w
    @starc0w 9 місяців тому +17

    If you have two pointers (one for the filename and one for the extension) you can calculate the length of the filename just by using pointer arithmetics.
    long long difference_in_elements = ptr2 - ptr1;
    long long difference_in_bytes = (ptr2 - ptr1) * (long long)sizeof(*ptr1);
    Note:
    The difference between two pointers is not in bytes, but in elements.
    Which amounts to the same thing for the char type on most systems. Because on most systems sizeof(char) is equal to 1.

    • @thebatchicle3429
      @thebatchicle3429 4 місяці тому

      This is wrong. The length of the filename is calculated like this:
      ptrdiff_t len = ptr2 - ptr1;
      The length is already in bytes.

    • @starc0w
      @starc0w 4 місяці тому

      @@thebatchicle3429
      No, the difference between two pointers is not in bytes, but in the number of elements (of the corresponding type).
      This is usually the type long long (signed) or int (signed). The result can also be negative.
      int array[2] = { 0 };
      int *ptr1 = array;
      int *ptr2 = array + 1;
      printf("%p %p %lld %lld %zu", (void*)ptr1, (void*)ptr2, (ptr2 - ptr1), (ptr1 - ptr2), sizeof(ptr2 - ptr1));
      //Out: 000000000027FB9C 000000000027FBA0 1 -1 8
      You must never implicitly assume that the size of a char corresponds to 1 byte. This may be the case in the vast majority of cases, but there are also systems on which this is not the case.
      That's why my example said "difference_in_bytes" and not "difference_in_characters".
      But your hint is still good, because in this context you would probably expect the difference in characters. Thanks for that, I will amend my comment accordingly.

    • @starc0w
      @starc0w 4 місяці тому +2

      @@thebatchicle3429
      The difference between two pointers is not in bytes, but in elements.
      That's why I wrote "difference_in_bytes" and not "difference_in_characters".
      However, your hint is still good, as in this context you would expect the difference to be in characters and not in bytes. Thanks for that, I've amended my comment.
      Cheers

    • @leightonmitchell2564
      @leightonmitchell2564 8 днів тому +1

      The standard says that sizeof(char) is always 1. However, it does guarantee how many bits char is. On most systems, CHAR_BITS == 8, but some might be 16 for example.

  • @opsJson_
    @opsJson_ Рік тому +2

    FUCKING DELICIOUS VIDEO! JUST LOVE C CONTENT!!!!!!!!!!!!
    THANK U, KEEP DOING IT

  • @iyadahmed3773
    @iyadahmed3773 Рік тому

    Amazing video!

  • @dimi144
    @dimi144 17 днів тому

    You should keep in mind that different types in C have different alignments when allocating memory, and that even though your code will work with or without taking alignment into account, misaligned memory accesses can degrade performance. Awesome video tho

  • @ahmadkhudai
    @ahmadkhudai Рік тому

    Good video 👍 thank you

  • @redcrafterlppa303
    @redcrafterlppa303 Рік тому +1

    Nice, I am just now starting to lay out the basics of a c style compiled language I'm planning to implement. I was looking around what allocation strategies to support but couldn't decide.
    In the past it was pretty easy either you garbage collect or use a malloc free system but nowadays there are so many niche competitors trying to revolutionize the game.
    Thanks to this video I might consider making arenas my primary allocation strategy.
    We will see ourselves again in 5 years when the language is mature enough to even work 😂

    • @voxelrifts
      @voxelrifts  Рік тому

      Nice! Good luck on your language. I would recommend having arenas for temporary or scoped dynamic allocations, and providing a malloc-like interface anyways because it is necessary in a few cases like dynamic arrays and such (unless you leverage virtual memory that is)

    • @redcrafterlppa303
      @redcrafterlppa303 Рік тому +2

      @@voxelrifts thanks.
      I was planning on allowing access to malloc and free anyway for potential c interop. Dynamic datastructures should ideally be part of the standard but I will see.

  • @MACAYCZ
    @MACAYCZ Рік тому

    Awesome video:)

  • @noorhashem7
    @noorhashem7 5 місяців тому

    Thanks for the great video! What debuger are you using in that video, is it a VSCode extention?

  • @emirbrkic6649
    @emirbrkic6649 5 місяців тому

    Great video

  • @johnjackson9767
    @johnjackson9767 7 місяців тому

    Cool stuff

  • @user-ot7pt9wf9d
    @user-ot7pt9wf9d 17 днів тому

    My C++ learning was stagnant. In order to learn C/C++ in depth, I turned to learning Rust. Now after watching your video, I found that these best practices are used by default in Rust community. I think This is the benefit of learning a modern language

    • @logicaestrex2278
      @logicaestrex2278 8 днів тому

      Rust is an entire language where a linter wouldve been sufficient lol

  • @slayerxyz0
    @slayerxyz0 Рік тому +3

    For jank templates I prefer the header file variation where you #define an argument (usually the type but any template parameter) for the template and include the template header. The template header uses the template arg to generate a bunch of functions and struct, then undefines all it's args. This way you can debug the code as you would normally because the function isn't created in a macro expansion.

    • @tiranobanderas5655
      @tiranobanderas5655 7 місяців тому

      one problem i have faced with this method that i dont know if there exists any fix for it is that if you want to for example include the template multiple times in your program simply for the declarations to use in other headers, include guards wont save you from multiple inclusion because the generated code is not guarded. Which means that you'd have to make a custom implementation header file with your own guards for one or multiple template specializations of the header file.
      If you know of any workarounds that avoid needing to make an extra file, i would be extremely thankful to hear of them.

    • @slayerxyz0
      @slayerxyz0 7 місяців тому

      @@tiranobanderas5655 There's an attribute you can use in GCC/clang for weak linkage. This basically makes the linker de-duplicate multiple instances of the same symbol across linked object files. This is basically what C++ does with template generated code (and is part of why C++ compilation is slow). Alternatively you can put prototypes in the header and ifdef guard the function implementations so that you can define a symbol to prevent the function implementations from being generated.

    • @tiranobanderas5655
      @tiranobanderas5655 7 місяців тому

      @@slayerxyz0 yeah, the second alternative is what i want to know how to do, but im not sure if im doing it wrong, because even if i make an implementation macro so that i can include only the definitions, the struct causes a redefinition of type problem.
      for example, if i have a generic dynamic array template header which i would use like this:
      //if i want to include the definitions as well
      #define T float
      #define IMPL
      #include "template.h"
      //if i only want the declarations
      #define T float
      #include "template.h"
      then, inside of the template.h file i would have a struct defined to use the data type defined for T.
      typedef struct {
      T *data;
      size_t len, cap;
      } STRUCT_NAME;
      then i would get a struct redefinition problem because the struct declaration itself is not within the ifdef guards.

  • @xhivo97
    @xhivo97 9 місяців тому

    I used pretty much the same approach for my data structures except that I used generic selection. Usually in C people would just use void pointers for the data and not bother with the macros, but I wanted to see what it's like. I like the type safety I get, and I imagine the compiler can do more optimizations knowing the type. I do wonder though, what if I use void pointer and generic selection based on type to get _some_ level of type safety and less generated code and potentially easier to debug. I need to experiment more.

  • @daviddawkins
    @daviddawkins Рік тому

    "...well it's all pain and suffering" :-D :-D. Great video, thanks.

  • @m4rt_
    @m4rt_ 5 місяців тому

    stb has a lot of useful header files for rading images, etc, you may find it useful

  • @aa898246
    @aa898246 Рік тому

    cool video

  • @jacquesfaba55
    @jacquesfaba55 5 місяців тому +1

    Sounds like Rust with extra added steps

  • @yogxoth1959
    @yogxoth1959 Рік тому +7

    I have some questions about how to use that string struct.
    1. How do you print a string that's not null-terminated?
    2. How do you get the length of the string? strlen (but that won't work if it's not null-terminated)? I assume you don't manually count characters.

    • @voxelrifts
      @voxelrifts  Рік тому +18

      Instead of using %s for printing a string, you can use %.*s which allows you to give it a size. I have a macro for str_expand(the_str), which just expands to `(int)the_str.size, the_str.str`.
      so what I can do is simply do printf("%.*s", str_expand(my_string));
      Length of the string is stored right within the struct so there's no need for strlen or counting.
      If you mean how I convert a string literal to a string struct initially, then I use a macro called str_lit which uses the sizeof() operator which returns the size for the string including the null terminator, then subtracting 1 gives me length of the string.
      github.com/PixelRifts/c-codebase/blob/master/source/base/str.h Lines 42 and 43

    • @yogxoth1959
      @yogxoth1959 Рік тому +5

      @@voxelrifts Exactly what I wanted to know. Thank you very much!

    • @voxelrifts
      @voxelrifts  Рік тому +7

      @@yogxoth1959 OK one thing I forgot to mention which is important, the str_lit macro only works on string literals, not char*s. If you want to convert a char* to a string type you have to use strlen. (This is because sizeof works differently specifically for string literals)

  • @rmt3589
    @rmt3589 5 місяців тому +1

    I'm only learning C for CS50x and to help with learning C++. Though I might come back to this video in the future, I'm gonna walk away for now. (Rn, I can't stop sneezing while this video is playing. Send help!!!)

  • @araarathisyomama787
    @araarathisyomama787 Рік тому

    Some template functionality can be emulated in C with function pointer parameters. As an example I have abused this approach to essentially create 25 versions of the same function in a single TU and it has worked really well. If I used C++ templates it wouldn't save me any LOCs there and the syntax is simpler.
    Function pointer sounds like an indirect call and indirect call doesn't speak performance, but don't worry. Compiler can and will optimize out hundreds of lines of code beyond comprehension if you give it a chance to do so.
    The compiler (Tested with GCC) can be easily encouraged and even forced to generate several versions of the same function and inline functions specified as function pointers or even inline the entire thing as long as definitions of both functions are visible in a single TU. This will generate essentially the same code as respective C++ templates or macro templates. You trade some flexibility as function pointers can't replace everything, but you can still do alot with those. You also get strict type safety and the same debugging experience as with your regular code.

    • @voxelrifts
      @voxelrifts  Рік тому

      Very interested to see this if you have a godbolt link or something

  • @heapninja
    @heapninja 7 місяців тому +2

    7:30
    Count-based strings have their benefits, but they come with tradeoffs. You're trading a 1-byte null terminator for 4-8 bytes of size for each string reference. It's a balance of pros and cons.

    • @voxelrifts
      @voxelrifts  7 місяців тому

      The "takes 3 bytes more" argument isn't that good though, now that we have gigabytes upon gigabytes of memory. There isn't any balance really, count based strings win at literally everything else I would say

    • @heapninja
      @heapninja 7 місяців тому +2

      ​@@voxelrifts In memory-constrained environments like Microcontrollers, wearables, and automotive systems, those 3-7 extra bytes per string reference can significantly impact resources & performance. It's crucial to choose the right tool for the job.

    • @voxelrifts
      @voxelrifts  7 місяців тому

      @@heapninja yeah, this video is definitely not going to be applicable for embedded systems. Arenas would also be unnecessary there, so would massive data structure templates.

    • @nobiado484
      @nobiado484 2 місяці тому

      That's the beauty of C. You can decide about those tradeoffs according to your specific constraints and needs.

    • @D0Samp
      @D0Samp 5 днів тому

      You can also do the std::string approach and squeeze a short string directly into the size field if you find a good way to distinguish both cases.

  • @kumarkumar-md7ee
    @kumarkumar-md7ee 5 місяців тому

    thx mate

  • @pokefreak2112
    @pokefreak2112 Рік тому +2

    Arena allocator is not necessarily a bump allocator. I've seen arena's implemented as a linked list of memory pages which works like this:
    - does the allocation fit in the page? bump current page
    - else create new page and allocate there
    then the arena_free traverses the list of pages and frees them
    supposedly you don't need this if you reserve (not allocate) a large chunk of virtual address space and put your allocations in there but I've yet to find a reference implementation online that actually does this

    • @voxelrifts
      @voxelrifts  Рік тому

      As I said, everyone seems to have different names. I heard many people call arenas bump allocators which I why I included them in the video. As for the large virtual memory reserve thing, that's exactly what I do for my arena implementation. I have 2 pointers instead of just one, a commit pos and an alloc pos

  • @stackercoding2054
    @stackercoding2054 5 місяців тому +2

    I just started learning C a week ago (I already work as a developer so I know how to code but never did anything serious with C), and this video literally answered the most important questions that I had regarding this language one by one, the youtube algorithm really nailed it this time.

  • @KangJangkrik
    @KangJangkrik 5 місяців тому

    Is arena aligned? If no, then it's definitely useful for implementing most communication protocols

  • @Little-bird-told-me
    @Little-bird-told-me 4 місяці тому

    I read K&R and I know little bit of C, now i hear about zig and odin and wonder if they are a better version C, or should I learn C and then move on to zig

  • @oh-facts
    @oh-facts 6 місяців тому

    Could you provide some more direction towards metaprogramming in C?
    Lets say I want to make something equivalent to
    template
    T vector_get(int index);
    this function would return the data stored at index in a vector
    So my metafile would generate vector_get multiple times for different data types?
    and after having my metafile generate the types, I would use the appropriate type where I need it? Do I understand this correctly?

    • @voxelrifts
      @voxelrifts  6 місяців тому

      Correct, the metaprogram is nothing but an additional layer used to generate code, which basic old C can understand

  • @darkfllame
    @darkfllame 5 місяців тому +1

    i really like C, until i saw Zig, zig was a very refreshing view on low-level programming, by default, zig standard library uses by default allocators, c_allocator, heap_allocator, and many more..., you can use any of them, also i really like zig's syntax, because it's a mix between C and OOP, but in a C-style: you have structs, structs can have fields, they can have methods (which are stored within the type, and not the object). every files are more or less giant structs. the only thing i don't really like in zig, is that there is too much builtin functions. I really like the comptime keyword though. anyway, if you like(d) C, you'll surely like zig.

    • @thewhitefalcon8539
      @thewhitefalcon8539 4 місяці тому +1

      Sounds like some c++ features

    • @nobiado484
      @nobiado484 2 місяці тому

      The special advantage of zig's comptime when it comes to templating is that you can use it for things that otherwise would require a separate 'templating part' of the language (often an entire different language), like we have in C, C++ and Rust. In Zig, you use the same exact language both for the code you want to ultimately compile and for the templates. In fact, you use the same language even in your build script! There's no gnu-make, nmake, cmake, autotools, meson, and so on. There's only Zig.

  • @yogxoth1959
    @yogxoth1959 Рік тому +1

    I'm trying to implement memory arenas right now and I asked ChatGPT what it thought about my arena_alloc function. It mentioned that the function would probably not handle arbitrary structs very well, because of alignment. I don't think you mentioned that in this video. Is this something I have to worry about?

    • @voxelrifts
      @voxelrifts  Рік тому +4

      Yes, but alignment in the allocator is also not hard. Just round up required allocated space to a multiple of a power of 2! Like 8

  • @ItsCOMMANDer_
    @ItsCOMMANDer_ 5 місяців тому

    it didnt watch the whole video yet , but gotta agree with the relativly small library, especilay string.h. at this point i acully decided to write my own stdlib like library (but focusing on adding better string functions and advances data types like linked list)

  • @mithrandirek1813
    @mithrandirek1813 Рік тому +2

    What are your thoughts about GNU AutoGen? I think it's a good solution, if you are not in a position to roll your own metaprogramming helper.
    And a lot of the times macros/codegen aren't even necessary considering how far link-time optimizations have come. The compiler can, in a way, generate the code for you, if it sees it fit.

    • @voxelrifts
      @voxelrifts  Рік тому +2

      I haven't heard of this actually, I should take a look. I used metadesk for making the tablegen program which was quite easy to set up and work with

  • @ShotgunLlama
    @ShotgunLlama 5 місяців тому

    Am I mistaken in that arenas still need a backing memory buffer, which you'd need to either have in static memory or still allocate on the heap, the latter requiring either using malloc anyway or using a system specific function?

    • @voxelrifts
      @voxelrifts  5 місяців тому +1

      You are correct, you need to allocate the backing buffer, either with malloc or with os specific calls like VirtualAlloc or mmap.

    • @nobiado484
      @nobiado484 2 місяці тому

      You will call malloc, but it will be only once for all the small objects that you will use, so it can be faster than several separate calls to malloc. It also helps to reduce memory fragmentation, as you can allocate arenas of a fixed size, regardless of the size of your smaller objects. And finally, you also reduce the number of times you call free(), which can also be costly and problematic. This helps both with memory management and performance, as you free all the objects from that arena at once, at one place. It's not ideal for every case, but it's very useful for the use cases he mentioned in the video.

  • @scienceexperimentsbyarvind9609

    Hello, bro. Would you be able to share the roadmap and the topics you have Learned to master C programming and graphics design using C ?. It would be so helpful for students like me 🙏🏼.

    • @voxelrifts
      @voxelrifts  Рік тому +3

      I don't have a strict roadmap per-se to be honest and I am still learning.
      For C I would recommend handmade hero's intro for starting off and just doing random projects in C to understand how to use it efficiently.
      For graphics learnopengl.com/ is an excellent resource for learning graphics programming, but more specifically OpenGL. Once you understand those, it's not hard to extrapolate to other graphics APIs.
      But an important tip is DON'T DO BOTH AT ONCE. Either learn C first, or learn graphics programming in your preferred language. Both topics have a lot of concepts you need to understand so mixing them together can be confusing.

    • @oliverfrank8124
      @oliverfrank8124 Рік тому

      @@voxelrifts Shout out Casey Muratori :)

  • @beeverfeever4930
    @beeverfeever4930 Рік тому

    quick question, what was that link about the metaprogramming?

    • @voxelrifts
      @voxelrifts  Рік тому

      Shoot I forgot to add that link to the description. I'll add it now, but here you go: www.rfleury.com/p/table-driven-code-generation

    • @beeverfeever4930
      @beeverfeever4930 Рік тому

      @@voxelrifts Thanks, great video.

  • @brontobytesdm9003
    @brontobytesdm9003 5 місяців тому

    The program everything search by void was said to be all written in C it is so fast at finding my files. I use blender a lot and model things and make cut files. C is used for robotics. Blender has Python. I am interested in writing code and want to understand what I am doing so I am starting with C

  • @zactron1997
    @zactron1997 9 місяців тому +2

    A lot of these are why I love using Rust. Explicit lifetime management, proper memory management, etc. all in a world where you don't "hope" that a library works as you expect.

  • @melvin4524
    @melvin4524 Місяць тому

    Can't you just iterate through the filename comparing to the ascii code for the . ?

    • @voxelrifts
      @voxelrifts  Місяць тому

      The problem isn't *finding* the dot, it's splitting the string at the dot. After finding the dot if you need a separate string representing just the filename, you'd have to replace the dot with a null terminator, which will break the string representing the entire filename with extension

  • @stolenlaptop
    @stolenlaptop Рік тому

    N strings or counter based strings don't need a structure. You just store the size in the first byte. This limits string size to 255 but is simple and lightning fast.

    • @voxelrifts
      @voxelrifts  Рік тому

      This has the same problem as with nullterminated strings where you have to make a new allocation for strings that are already there. If you follow through with my example, you'd have to allocate for the extension string instead of filename string which is what the struct avoids

    • @stolenlaptop
      @stolenlaptop Рік тому

      @@voxelrifts if you're receiving null terminate strings. You just offset by one to receive and send null terminate strings then using your own libraries manipulate everything using the n count. It's not the same as it adds another facet. In many ways it's like using a structure except without the pointers needed to manipulate as it's all in one character array. In fact you can chain them that way too.

    • @voxelrifts
      @voxelrifts  Рік тому +1

      @@stolenlaptop Firstly, I don't know what you mean by facet. Secondly I think you missed my point :)
      Circling back to the example I gave in the video, we had the full filename with extension as an allocated string and wanted strings that are just filename without extension and just extension without filename the problem with placing count right before the characters of the string is the same as having a null terminator at the end of the string. Infact having the count roght before the allocation is much worse because the count for filename without extension and filename with extension will have different sizes but would have to be stored in the same location if you want to refer to the same allocation. The structure solves this because you're keeping sizes on the stack itself rather than alongside the string data

    • @dandan-gf4jk
      @dandan-gf4jk Рік тому

      @@voxelrifts I took it as, you can encode the length of the view in the lowest byte of the pointer, which is a more interesting approach. Doing so in the lowest byte isn't as good as your strings probably aren't 256 byte aligned and you can kiss goodbye having a different offset, but you could totally use the upper 24bits of the pointer as they are for the most part irrelevant in the userspace. Of course this necessitates having functions or at least a macro that would encode/decode the pointer for use.

  • @NootNooter
    @NootNooter 5 місяців тому

    That big macro for templates is *extremely* scuffed. Just use void ptr or use inheritance

  • @SimGunther
    @SimGunther Рік тому

    There is a weird way to do strings, but it works:
    struct string {
    size_t len;
    char data[1];
    }
    Now if you want to allocate a string, you can do the following:
    #define STR_LENGTH 5
    struct string* greeting = (struct string *)malloc(sizeof(struct string) + STR_LENGTH);
    /* NULL terminate end of string */
    greeting->len = STR_LENGTH;
    greeting->data[STR_LENGTH] = 0;
    /* TODO: Fill in data with your actual string */
    Don't forget to free that memory with free(greeting) and create a macro template for this special kind of string ;)

    • @voxelrifts
      @voxelrifts  Рік тому

      This also seems to have the same issue of needing new allocations for simple "views" into the string, since the count and string data is right next to each other.

    • @SimGunther
      @SimGunther Рік тому

      If it's a view you want, you'd just need a tag struct such that:
      size_t len;
      const char* const data;
      Now we made it clear that we can't change either the characters in the data or the pointer to the character array so we can init the data struct in an initializer list instead of direct assignments. Can't believe that's the monstrosity we need for simple "views".

    • @voxelrifts
      @voxelrifts  Рік тому +2

      @@SimGunther Right. The point of the string struct in the video was to not have to have two separate structures for regular strings and views :). Quite helpful in many many cases I've found

  • @xarcaz
    @xarcaz 22 дні тому

    Any plans on re-recording this with a decent mic?

  • @anon_y_mousse
    @anon_y_mousse Рік тому +1

    This is certainly an interesting technique, though I would suggest using pre-existing libraries when possible. For memory allocation, unless you absolutely need it to be as fast as possible, using a GC library for those that can't or don't want to manually manage memory, would be my recommendation. Hans Boehm wrote one that you might consider looking into. For string handling, it's a good idea to do the same, finding a library that suits your style but that stores the length.
    All that said, data structures are the real crux for people new to the language. Most people either don't learn them properly or at all in school, and not just the implementation, but the selection of, can have a huge impact on performance and memory usage. There's plenty of videos that go over some of the vagaries of selection, but they're often too general purpose and truthfully, I often mix and match to make hybrid structures anyway. It'd be great if someone could make a video series on implementing some of the more obscure data structures and how to mix and match them for more effective design.

    • @voxelrifts
      @voxelrifts  Рік тому +5

      Why find a library if writing one yourself is just as fine?

    • @anon_y_mousse
      @anon_y_mousse Рік тому +1

      @@voxelrifts Laziness.

    • @voxelrifts
      @voxelrifts  Рік тому +1

      @@anon_y_mousse lol

    • @justadude8716
      @justadude8716 Рік тому

      Also because I enjoy actually making stuff rather than laying bricks for hours

    • @voxelrifts
      @voxelrifts  Рік тому +4

      @@justadude8716 It doesn't really take long and does help to get better at understanding memory and other important things if you do do things yourself sooo ¯\_(ツ)_/¯

  • @varunvishal
    @varunvishal Рік тому

    As a 23 year old with no college education so far and no skills other a basic High School education.
    How would you recommend someone go about learning programming and Mathematics?

    • @voxelrifts
      @voxelrifts  Рік тому +5

      I don't think I'm qualified to give advice to people to be honest, but I think doing projects that interest you is the best way to learn programming. For both maths and programming, the only way one can get better is with practice :)

    • @varunvishal
      @varunvishal Рік тому

      @@voxelrifts Thank you for taking the time to write this.

    • @varunvishal
      @varunvishal Рік тому

      @@voxelrifts will be looking for your content in the future. Keep up the good work.

    • @thomasjensen9581
      @thomasjensen9581 Рік тому +1

      In practicality i think finding some in-person courses is the safest path to get into the business, but if you want to learn for free: programming is a huge field, it really boils down to "what" you want to program, i would say your first step is to identify what area you want to target, like web, back end, embedded, etc. and then i would recommend watching getting started videos on youtube, once you got the basics of your language i would recommend to work on and learn code etiquette (software development is about making clear and understandable code, not just code that works), then get a portfolio going and hope it is enough to get a job

  • @nevokrien95
    @nevokrien95 3 місяці тому

    Shouldn't you be passing a size to the arena? Seems like a small string is gona take diffrent sizes tha. The full thing

  • @AnzenKodo
    @AnzenKodo 5 місяців тому

    super cool channel, but only thing that is not cool is having atom editor(made in javascript) logo.

    • @voxelrifts
      @voxelrifts  5 місяців тому +1

      Lol, it is probably time to change it

  • @jkf16m96
    @jkf16m96 Рік тому

    Macro templates are really wacky.
    I prefer to use void* and size_t, even if it gets really hard.

  • @ensiferrus9090
    @ensiferrus9090 3 місяці тому

    9:35 `void type##_slice_subslice(...);\`
    "void"? Are you sure about that? [0]
    9:50 `type##_slice_subslice(slice, idx)`
    Are you sure about that? [1]

    • @voxelrifts
      @voxelrifts  3 місяці тому

      Yep, yep, that was a mistype

  • @NeZversSounds
    @NeZversSounds Рік тому +1

    I love C because it's not bloated and handcrafting everything sometimes feels fun. But I'm unable to build complex because I can't wrap my head around header inclusion organization. Setting makefiles is tedious and a pain in the ass to set up 3rd party library inclusion.

    • @voxelrifts
      @voxelrifts  Рік тому

      You might want to watch my latest video about compilation and how that whole system works!

  • @ArtoPekkanen
    @ArtoPekkanen Рік тому

    Instead of generating code within a function-like macro body, use generator headers intead. Much easier to read and maintain, and no need to spam \\\\ unti your head explodes. Example of generator header:
    #define _CAT3(a,b,c) a ## b ## c
    #define CAT3(a, b, c) _CAT3(a, b, c)
    #define FN(name) CAT3(GEN_ARG_NAME, _, name)
    #include
    struct GEN_ARG_NAME {
    GEN_ARG_TYPE* data;
    size_t size;
    }
    int FN(push)(MTL_ARG_TYPE *o, MTL_ARG_TYPE v) { ... }
    #undef _CAT3
    #undef CAT3
    #undef FN
    #undef GEN_ARG_NAME
    #undef GEN_ARG_TYPE
    Later you can instantiate the template by setting a few macros and including header, like this:
    #define GEN_ARG_NAME intvec
    #define GEN_ARG_TYPE int
    #include
    ...
    intvec iv = {0};
    intvec_push(&iv, 42);
    ....
    Get the idea?

  • @gorenbk
    @gorenbk 4 місяці тому

    Is a linear allocator… just a stack?

    • @voxelrifts
      @voxelrifts  4 місяці тому

      Can be implemented as one easily yeah!

    • @gorenbk
      @gorenbk 4 місяці тому

      @@voxelrifts wait i dont get it. is the normal rsp thing with a push instruction that most CPUs give you by default an arena allocator?

    • @voxelrifts
      @voxelrifts  4 місяці тому

      @@gorenbk Well not exactly, an arena is an arena if you free the memory all at once. If you want to pop off memory it wouldn't be an arena, but instead it'd be a stack allocator. Also I wouldn't call push/pop instructions "allocator functions" at all.

  • @shivangupadhyay8002
    @shivangupadhyay8002 Рік тому +12

    zig my friends zig

    • @Marius-ir1qn
      @Marius-ir1qn Рік тому

      ugly language

    • @ovi1326
      @ovi1326 Рік тому

      zig indeed

    • @airbus5717
      @airbus5717 Рік тому +1

      lol, the problem with zig is that u only get what LLVM generates for u
      hopefully, it will change in the near future

    • @PixelThorn
      @PixelThorn 11 днів тому

      ​@@airbus5717yeah well, better than whatever this is

  • @Jimmy9Bazooka
    @Jimmy9Bazooka Рік тому +2

    Arena and bump allocators are completely different. Bump allocator is just stack. Arena allocator can use any allocation strategy within itself, but it's point is that you destroy the whole block and all allocations within it in one call.

    • @marcs9451
      @marcs9451 Рік тому +1

      To be fair, these terms are not that rigidly defined, in fact you even used the term "stack" that implies a LIFO behavior thay is not the case with a Linear/Bump/Arena allocator.

  • @MrOnePieceRuffy
    @MrOnePieceRuffy Рік тому +1

    Thumbs up, because the Video itself is good but the sad truth is I never made something in Rust yet, but I program since 20 years, just randomly saw this and i want to say:
    If you know C already, then you shouldn't need this Video and if you don't, learn Rust.

  • @MrAbrazildo
    @MrAbrazildo Рік тому

    3:45, why do you need to "registry" the pointers? Once they are != NULL, you can presume they have memory allocated. 3:56, I guess you are trying to detach a,b,c from the struct, maybe throwing them in global space? This is terrible idea!
    4:14, so this "arena" won't ever be used just for reading/writing, but only for allocations?
    4:37, I don't use C anymore, so I don't recognize this 'string' type for it. But I didn't get in which way arena helped here?
    6:58, just create a tiny f() for the extension:
    const char *get_ext (const char *FileNameAndExtNoDot)
    { return FileNameAndExtNoDot + strlen (FileNameAndExtNoDot) + 1; } //It'll point after the dot.
    So the printf would be:
    printf ("%s.%s", name, get_ext (name));
    9:33, it's a nice idea to not put the last ';' in a macro, to be forced by the compiler to put it on each call. It feels more like a normal cmd.
    And there's a bug: you can't put the last \, because the macro ended before it.
    I didn't find this ERROR macro(?). Anyway, you could use assert, from , instead of if, and you would be dismissed from having to write an error message. It would just be shown as a failure of that if-logic.

    • @voxelrifts
      @voxelrifts  Рік тому

      The pointers are not going in global space at all. They're going in an arena which has a lifetime that lasts from the init function to the free function. We get rid of the need to call free on those pointers manually. It might not be a big win just for random integers, but things for things like linked lists it is very helpful since you don't need to traverse the list freeing every node. Basically removing the dependency on the pointer for memory freeing
      About 4:37 it's a custom type, as you probably saw from later in the video
      About 6:58 yes in this case you can print it piecewise but it's not an actual allocated string anywhere which is necessary many times.
      ERROR was just a placeholder since I was showing pseudocode here. You're free to use whatever error handling you want!

    • @MrAbrazildo
      @MrAbrazildo Рік тому

      ​@@voxelrifts But you still need to write at least 1 time a free f() for this arena. And if it deals with linked list, the same thing about traversing the nodes, right?

    • @voxelrifts
      @voxelrifts  Рік тому

      @@MrAbrazildo yes you free the arena. But if you allocate all the nodes in the arena, you don't have to iterate through the list and free all pointers one by one. Instead you free the entire arena and all the nodes allocated within it are automatically freed

    • @MrAbrazildo
      @MrAbrazildo Рік тому

      ​@@voxelrifts If I would spend time making such thing, I would build a stack version of it: a struct carrying an array and several pointers, 1 for each part of it. And an internal control, compiled in a separated file.

    • @voxelrifts
      @voxelrifts  Рік тому

      @@MrAbrazildo I don't think I get what you're describing

  • @thomasjensen9581
    @thomasjensen9581 Рік тому

    These things are basically the stuff i do all the time when i write in c, while being super good knowledge, most people would probably just use a garbage collected, probably interpreted language with a large set of standard libraries and call it a day

    • @voxelrifts
      @voxelrifts  Рік тому +1

      And that's completely fine! I just wanted to share these techniques because they're never really explained/told for some reason, and because they make a huge difference from my experience.

  • @PixelThorn
    @PixelThorn 11 днів тому

    Leave it to a C programmer to reinvent what's already implemented and solved in C++

  • @uvadroid
    @uvadroid Рік тому +1

    What a wonderful nightmare

  • @seethekek4647
    @seethekek4647 Рік тому +1

    sorry, but instead of having to allocate 8 bytes for a "string", you could just know where the string ends by knowing where the extension is, and just extract one from it.

    • @voxelrifts
      @voxelrifts  Рік тому

      How do you extract part of a string without allocation? You *have* to allocate it somewhere else for null termination to work

    • @seethekek4647
      @seethekek4647 Рік тому

      @@voxelrifts you dont

    • @voxelrifts
      @voxelrifts  Рік тому

      @@seethekek4647 uhh you're talking about null terminated strings correct?

    • @seethekek4647
      @seethekek4647 Рік тому

      @@voxelrifts yes

    • @voxelrifts
      @voxelrifts  Рік тому

      @@seethekek4647 then I need more explanation here because I'm pretty sure it's not possible to not have to allocate the substring separately

  • @xyve6129
    @xyve6129 5 місяців тому

    "...not having a good standard library" sure... Even languages aiming to replace C, like Rust, still have to call down to C's malloc() lol

  • @Tekay37
    @Tekay37 Рік тому +1

    You lost me at the #define. I'm not sure what it is about them, but C/C++ Makros just make me giving up on these languages every time.

  • @illegalsmirf
    @illegalsmirf Рік тому +4

    Standard question for all C users: why aren't you using C++?

    • @voxelrifts
      @voxelrifts  Рік тому +7

      Compile times and too many features that don't need to be there. The features that I do need, I can write in C so I don't really mind

    • @oleksandrnahnybida3167
      @oleksandrnahnybida3167 Рік тому +3

      because C works good enough to not bother with C++

    • @thomasjensen9581
      @thomasjensen9581 Рік тому +7

      C++ offers a lot of inconveniences disguised as language features, as an alternative to writing simple data oriented code design in c, where everything is clear and in front of you, and you know what is going on in terms of what is executed and how it gets optimized by the compiler, you are offered objects with automatic operators obfuscating code clarity, incomprehensible inheritance hierarchies obfuscating code clarity, runtime template related errors that is going to take you forever to solve, namespaces where you either have to choose between insanely long lines of code or risk not knowing what library a generic function name comes from.
      My point is that c does exactly what you want it to, is easy to write and read due to less syntax complexity and limits you in terms of features so that you cant write an overly complex solution to a simple problem.
      C++ is not inherently evil, it is just a language that has seen so much feature creep that understanding how to use all the tools efficiently is impossible.

    • @tenderZeitGeist
      @tenderZeitGeist Рік тому +2

      Guys, guys! It is a trap... oh no.

    • @Unit_00
      @Unit_00 Рік тому +4

      I got tired of getting error messages from the compiler that looked like an ancient eldritch language. I'm mostly interested in making games (maybe with like a custom software renderer or something like that) and C's features have been just enough.

  • @PrivateUsername
    @PrivateUsername 5 місяців тому +1

    And, of course, everything you show here undoes the main benefit of C - it's low memory footprint. That string implementation adds 8 bytes to every string. So now "HELLO" goes from consuming 8 bytes (5 char, 1 null, 2 pad) to 16 bytes. You've doubled the memory footprint for no real benefit.

    • @voxelrifts
      @voxelrifts  5 місяців тому +3

      "No real benefit"? I did show in the video how that reduces the memory footprint effectively by you not having to make separate allocations per substring. Also 1 byte is not a lot of memory to "waste" if you even call this wastage.

  • @ghostbusterz
    @ghostbusterz 7 місяців тому

    Why is a size not specified when making an arena? How is that even possible since malloc requires a size?

    • @voxelrifts
      @voxelrifts  7 місяців тому +2

      There's a few ways to do this.
      A) Assume a size, like 1 megabyte or something. No complications.
      B) Make arenas hold a linked list of malloc-ed chunks of memory. So if you exceed one chunk, you alloc a new one and use that.
      Or C) the one I use, using virtual memory. This allows me to VirtualAlloc a large chunk of memory to reserve that address space (like 1 gigabyte). This doesn't actually allocate that memory though. When space is required I commit part of that reserved memory which actually allocates it to my process like malloc does. This keeps things contiguous in address space and I don't have to worry about passing sizes around since 1 gigabyte is quite a bit of space. Of course, I have additional functions that can allocate an arena with a specified size but that is rarely required.

    • @ghostbusterz
      @ghostbusterz 7 місяців тому

      @@voxelrifts Ah, very cool, never realized I could do that. But is virtual allocation part of the standard library or is it Windows-specific? To put it another way, can I achieve "cross-platform" virtual allocation?

    • @voxelrifts
      @voxelrifts  7 місяців тому +1

      ​@@ghostbusterz It's not in the standard library no, but mmap is the way to do so in any posix compliant OS. so I just have helper functions for reserve, commit, decommit and free, which call either mmap/munmap for posix OSes, and VirtualAlloc/VirtualFree for windows.

    • @ghostbusterz
      @ghostbusterz 7 місяців тому +1

      @@voxelrifts Got it. I use SDL2 so I imagine it's very likely it has something of the sort.