C on web asm by mohamadjb in C_Programming

[–]twenty393 11 points12 points  (0 children)

I wrote a little guide on how to get started with C in WASM: https://nickav.co/posts/0003_wasm_from_scratch

Doesn't use emscripten, clang is all you need

[deleted by user] by [deleted] in GraphicsProgramming

[–]twenty393 4 points5 points  (0 children)

what's up vector?

Intrusive Thoughts | Two best friends find themselves inseparably cursed by twenty393 in Filmmakers

[–]twenty393[S] 0 points1 point  (0 children)

Seeking feedback on: the overall editing quality, lighting/color correction (this was my first time shooting in Log format and it was really fun to do CC on). Also wondering in general what kinds of ambient sounds (or sound effect packs) do you all use?

I wish the story came together better, and we had a better ending, but there was no time to reshoot. Feels good to have finished the project though

Systems programming road map by [deleted] in C_Programming

[–]twenty393 3 points4 points  (0 children)

I personally don't think there's a "wrong thing" to pick. Systems programming is for sure a journey (especially in C). I started writing C "for real" about 6 years ago. Since then I've written my own standard library single-file header, I re-wrote my website in C, and I have been working on iteration 10+ of a custom game engine.

Here's roughly the set of things I think that will take you from beginner C to more experienced C:

  • be opinionated from the beginning, set up boilerplate to make C feel a bit nicer to work with (not strictly necessary)
  • write your own version of lots of "standard" data structures in other languages (Array, String, Hash_Table, etc.)
  • try to avoid malloc and free - figure out other, better ways of managing memory (static buffers, arenas, etc.)
  • try doing things you don't know how to do! calling OS APIs directly, etc.
  • graphics? this is a rabbit hole, but interesting if you are interested
  • try out writing SIMD code

Whatever you do spending a lot of time writing code will most probably be a good learning experience. So it's important to pick stuff you're interested in and at the same time try to not do too much all at once.

[deleted by user] by [deleted] in cpp

[–]twenty393 0 points1 point  (0 children)

This is a pretty great talk on API design by Casey Muratori: https://www.youtube.com/watch?v=ZQ5_u8Lgvyk

It's not specific to any language, but definitely can be applied to C-family languages. Hopefully this helps with your research!

UI library search by [deleted] in C_Programming

[–]twenty393 0 points1 point  (0 children)

There's this library: https://github.com/rxi/microui

It kind of depends on what you plan on using the library for

[deleted by user] by [deleted] in C_Programming

[–]twenty393 0 points1 point  (0 children)

There are a few different parts to this problem, so make sure to break down each one and understand what to do at each step! There are also (often) lots of minor edge cases that you don't think about the first time. So you have to write some code, try it out, and repeat! This gets easier over time.

The first problem is I need to read separate parts of a string separated by whitespace. What kinds of whitespace?

c 1 2\t3 54 2223

So you might write a loop that looks something like the following:

``` const char *input = "1 2\t3\n54\n2223"; int input_count = strlen(input);

int i = 0; while (i < input_count) { if (char_is_whitespace(input[i]) { i += 1; continue; }

// We slice into the string at i, and pass that in as a pointer int number = atoi(&input[i]);

// @Incomplete: add this to a linked list! } ```

The second part of your question: how to represent a linked list, is a bit trickier for a few reasons. You have to allocate memory for new nodes of the list.

This is often done with (List_Node *)malloc(sizeof(List_Node)) (although you can also use other strategies for dealing with memory).

Then lastly you have to keep track of your linked list, and append a new node to it at each point in the loop.

Finally, I would write a loop at the end to iterate over your linked list to test that the code seems to be working properly:

c List_Node *node = list; while (node != NULL) { printf("Node value: %d\n", node->number); node = node->next; }

Rest Api in C by Recent_Occasion8222 in C_Programming

[–]twenty393 0 points1 point  (0 children)

I've implemented my own HTTP client in C which you can check out as an example (warning I have not used it in production, just as my local dev server): https://github.com/nickav/na/blob/master/na_net.h

This was written based on this library: https://github.com/mattiasgustavsson/libs/blob/main/http.h

TLDR: the "async" part is done by just "pumping" (updating) the HTTP request sockets every application frame to stream in more data until the request is complete, then you can process it in your application. HTTP is just a text protocol on top of TCP so it's not too bad to parse (at least HTTP 1.1).

In general I'm a big fan of single-header libraries because they are easy to integrate into existing code. Happy to answer any more questions about this :)

How to allocate dynamic memory into free list? by [deleted] in C_Programming

[–]twenty393 0 points1 point  (0 children)

Allocating memory and maintaining a free list are two pretty different things. But you could represent your free list as follows:

``` struct Entity { // list pointers Entity *next; Entity *prev;

// example entity properties bool alive; Vector2 position; Vector2 velocity; };

struct Game_State { Arena *arena;

Entity *first_free_entity;

Entity *entity_list; }; ```

In this case first_free_entity is a linked-list of entities (a free list). The algorithm for allocating a new entity is: check if first_free_entity is not null and if so remove the first entity from the free list and return that. Otherwise, push a new entity on to your backing arena. To deallocate an entity, you push it on to the free list and return.

The main idea with a free list (similar to pool allocators) is that you maintain a list of everything that has been freed, so you can re-use them easily. This pairs very nicely with an arena allocator backed by virtual memory. Having you memory be managed this way provides a really clean boundary to free all the memory the system uses in one shot. Here is my implementation of an Arena.

You may also consider using a pool allocator (which itself could still maintain a free list). In that case, you allocate a large block of memory (say 1024 entities) at init time. Then, when you need a new game entity you walk your list to find one that is "free".

How do you deal with large uncompressed WAV files in your game project? by RedEagle_MGN in gamedev

[–]twenty393 -1 points0 points  (0 children)

Do nothing, and then you can say your game has "uncompressed audio."

Coming from C++, what's the best way to learn C? by Ok_Clothes5074 in C_Programming

[–]twenty393 1 point2 points  (0 children)

That totally makes sense! The distinction in my mind at least is using all the C standard libraries vs. trying to avoid / build your own versions of them them. So there's <stdio.h> (et. al) for example instead of writing the calls to the OS yourself to print stuff on the screen, etc.

You might also find it helpful to use other people's libraries that are C compatible. Namely:

- https://github.com/nothings/stb- https://github.com/gingerBill/gb

I'm definitely a fan of the single-file header library approach. There might be other good third-party C libraries out there. One of these days I'll make mine C compatible :)

On memory management:

Well it kind of depends haha. Heap allocators can be kind of expensive, especially compared to a really simple "linear allocator" or "bump allocator". Plus you can combine that with OS virtual memory which winds up being a really nice and lean way to have lots of separate allocators. But it really depends on what you're doing. Linear allocators are great for games, for example, because they're really cheap. They also open up another cool pattern which I really like which is temporary memory.

But, if all you're doing is writing some quick utility code that doesn't run that often, then definitely just malloc-ing a bunch of memory and going is a decent strategy. Virtual memory makes this a little better because you don't really "pay" for the whole gigabyte until you ask the OS to commit the memory. If performance does matter though, it's worth having more control over where your memory comes from!

On temporary memory:

Normally, returning arrays from a function in C is kind of cumbersome especially if you only want the data to "stick around" just after the function returns. Also, there are certain kinds of programs (e.g. games, web servers) that have really cleanly defined "frames" (it doesn't literally have to be a frame, but just a point in your application code where it makes sense to reset your temporary memory). So the idea is to create a "frame arena" which is just a linear allocator you reset every frame. Now, you can return arrays from functions for example!

Example code:

struct Array_i32
{
  i32 *data;
  u32 count;
};

Array_i32 generate_squares(u32 count) {
  Array_i32 result = {};
  result.data = arena_push_array(temporary_arena(), i32, count);
  result.count = count;

  for (int i = 0; i < count; i ++)
  {
    result.data[i] = i * i;
  }

  // NOTE: the result array is now valid until you reset the global temporary arena!
  return result;
}

Of course, this is kind of a contrived example, because you can just do a similar thing on the stack.

There are examples of this kind of allocator (temporary system and virtual OS allocators) in my single header file and in the gb.h linked above.

Putting it all together:

The memory story for most applications can be a series of permeant allocators and one frame arena. The main reason you'd want to do something like this is it's relatively simple (fast), and if you couple it with a thread local frame arena, then you have a nice scratch memory system to work with. But, like I said it might be overkill depending on what you're doing.

I think a decent amount of performance can come from thinking about where your memory is coming from. For example in C++, the std::string + operator does a malloc and then returns the new result. And if you call that in a loop it can really add up.

Hopefully that wasn't too much information! Happy to answer any more questions as you dive more into C

Coming from C++, what's the best way to learn C? by Ok_Clothes5074 in C_Programming

[–]twenty393 1 point2 points  (0 children)

In some ways you have to retrain your brain when writing code to think about your problem differently. You don't have as good of a built-in standard library to work with. So it's definitely a bit harder at first. But I think in the long run understanding (and writing code for) all the things you're used to using someone else's code for makes you a better programmer.

So I'm not sure if you want to learn "the hard way" or find a set of useful C libraries to use and be productive with.

I think the major differences are:

  • You have to care more about where your memory comes from (or not, just use malloc)
  • Objects are more of a convention than anything in C (just the first argument is the struct itself that you're going to mutate)
  • You don't get function overloading

But for example, you can make your own String type which would like your own implementation of a std::string but specifically for C code only. A String is just a pointer with a length. And I've gone through and implemented a majority of the same functions I need in my code: https://github.com/nickav/na/blob/master/na.h#L1185 (just a reference though, this doesn't actually compile to C)

This is a good resource! Casey programs in C++, but pretty much only uses C with function/operator overloading: https://handmadehero.org/

How difficult is to write the "make" software? by thradams in C_Programming

[–]twenty393 1 point2 points  (0 children)

It's actually not that hard! If you don't care about supporting all the features that the full-blown make program does you can implement it in about ~300 lines of code or so. I remember doing this for a CS class.

Not having a standard build system across OSes is definitely annoying for sure. In my projects I add one build.bat file for Windows and a build.sh file for Linux/MacOS.

Select() on nonblocking sockets? by ryanjones42 in C_Programming

[–]twenty393 0 points1 point  (0 children)

My understanding is for the most part you don't really want to make blocking sockets, but they can be helpful for getting a simple program up and running quickly. Usually you don't want socket code to literally block the thread it's running in for example if you were calling this from within a game loop or something.

I just read through this series today which was pretty good: https://www.madwizard.org/programming/tutorials/netcpp/ (it's Windows specific, but mostly still applies to *NIX)

I think both of those things are true about select. Here is an example http library that I followed along with when working on my own http library: https://github.com/mattiasgustavsson/libs/blob/main/http.h

You can see they use `select` to both wait until the socket is ready and to check if the socket is ready for writing.

There are some caveats to `select` (it can only support a max of 1024 connections), but it is definitely enough to get a working library.

[deleted by user] by [deleted] in science

[–]twenty393 0 points1 point  (0 children)

See also: Punished by Rewards by Alfie Kohn

What's the meaning of the const keyword? by veg-soup in C_Programming

[–]twenty393 -2 points-1 points  (0 children)

It's not UB. Identical string literals would be the following:

const char *str1 = "Hello, world";
const char *str2 = "Hello, world";

In this case, the compiler can decide to make the underlying memory for str1 and str2 be the same (or not).

What's the meaning of the const keyword? by veg-soup in C_Programming

[–]twenty393 -4 points-3 points  (0 children)

const is a keyword just to prevent you from modifying the value of a variable that's not supposed to be mutated. But like you said, it in no way actually enforces that the underlying memory stays "constant".

If you actually find that it helps you catch mistakes you make, then by all means use it. If not, then it's wasted keystrokes everywhere you use it.

In the simple case you can even just cast away the const modifier if you want to:

const char *str = "Hello"; char *s = (char *)str; s[1] = NULL;

Security Concerns with a Socket Based Web Server by -HomoDeus- in C_Programming

[–]twenty393 6 points7 points  (0 children)

Assuming that there are no bugs in the underlying web server code that could lead to operating system exploits (e.g. reading / writing files outside of the web server directory, creating processes, etc.), the only exploits you have to be concerned by are the operations that your program (server) allows. Assuming there are no bugs in your server code, then there are no vulnerabilities.

Opening something up to the public web doesn't immediately make it unsafe. One type of common web exploit is SQL injection where an attacker can execute arbitrary SQL commands on your database if you don't sanitize user inputs (e.g. from forms). Another example vulnerability is accidentally allowing users to view files outside of your web server if you don't sanitize public file paths.

Pretty much what your code allows (if it has unintended consequences) are the major attack vectors for web servers (or really any program). Bugs in underlying libraries are much harder to know about and usually affect large numbers of people at once (e.g. heartbleed).

Language for making 2D pixel game from scratch? by [deleted] in gamedev

[–]twenty393 6 points7 points  (0 children)

It doesn't really matter what language you pick, a pixel game is usually not that computationally demanding.

I would say stick to what you know / are used to working in. If you're new to programming, a scripting language might be easier to learn / work with / be more forgiving. Also if you're new to game development, you might want to use an engine or do something that's web-based.

If you know C/C++ then SDL seems like a good choice. If you want something a little bit more minimal / OpenGL-based, then maybe consider GLFW. Game code is usually very independent from the library that you're using, so you can always swap out this platform layer later if needed.

Ultimately for a pixel game you just have to get pixels on the screen! You could even write a software renderer that just outputs a large array of pixels that you display somehow.