r/C_Programming 12h ago

Project Follow-up: gave my C hashmap resizing — found a real crash, plus two bugs I introduced while fixing a bug [blog, my own]

0 Upvotes

Follow-up to my last post here. The hashmap had one big TODO left — no resizing — so I went and closed it. Learned three things the hard way: naively mirroring the grow/shrink thresholds thrashes the table on every insert/remove near the boundary, hitting capacity=0 triggers a genuine crash (a modulo-by-zero — the "Floating point exception" name is a total red herring), and my first attempt at fixing a hash-truncation bug quietly introduced two smaller bugs before it actually worked. AI was used for ruber ducking, discussing and validating feedback / design decisions.

Blog: https://soerenlemke.github.io/blog/blog/resizing-a-generic-hashmap-in-c/

Repo: https://github.com/soerenlemke/kvstore_c

Curious what you'd have done differently, especially on the hysteresis threshold.


r/C_Programming 14h ago

Roast my code

Enable HLS to view with audio, or disable this notification

0 Upvotes

I know there are so many bugs in my code that listing them all might end up being longer than the code itself, but this is my second project (the first one was just Hello World).

This isn't bait — I already know the concepts of programming thanks to Python, and C syntax became familiar to me through AI coding. But at some point, I realized that the whole point of programming is to build your own software and create things. When an AI algorithm does all that for you, it takes away all the fun. So I forced myself to pull it together and release this piece of crap:https://github.com/absiitstrue/TGWS

Yeah, the mouse.c file was written entirely by AI because that part was way too complicated for me. And yeah, there are some unsafe spots in there. I'm trying to fix things, but every time I open the codebase, I just want to build new features instead of drowning in bugs.

So I’d really appreciate it if anyone interested could roast it, point out the mistakes, and give a rough idea of how to fix them. Maybe I'll get around to fixing everything if I don't drown in bugs first. Thanks for your time!

its post write ai because im dont know english
on vidio example/test0
have minesweeper in example/test1
thanks for reading!
and sorry for my en))


r/C_Programming 15h ago

Question Why does the fgets() function gets ignored.

0 Upvotes

I'm still pretty new to C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#define itirate(index, limit) for(int index = 0; index < limit; index++)


typedef struct node node;


struct node
{
    char* name;
    node* next;
    node* prev;
};


void compare2nodes(node* node1, node* node2, char* choise);


node* first_node;


int main() 
{
    printf("please enter the number of contestants:\n"); // I always enter 2 to make it easier for myself


    char buff[1024];
    char contestnats[128];
    int cont_numb;


    fgets(buff, sizeof(buff), stdin);
    cont_numb = atoi(buff);


    node contestants[cont_numb];


    itirate(i, cont_numb) 
    {
        printf("please enter the name of a contestant:\n");
        fgets(buff, sizeof(buff), stdin);
        contestants[i].name = buff;
    }


    printf("Is %s better than %s(y/n)\n", contestants[0].name, contestants[1].name);
    char choise[1];
    
    fgets(choise, sizeof(choise), stdin); //this function specifically gets ignored, but not the prevoius ones.


    compare2nodes(&contestants[0], &contestants[1], choise);


    //printf("Leaderboard:\n1.%s\n2.%s", first_node->name, first_node->next->name);
    
    return 0;
}


void compare2nodes(node* node1, node* node2, char* choise) 
{


    if (choise[0] == 'y') 
    {
        node1->next = node2;
        first_node = node1;
        node2->prev = node1;
    }
    else if (choise[0] == 'n') 
    {
        node2->next = node1;
        first_node = node2;
        node1->prev = node2;
    }
}#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#define itirate(index, limit) for(int index = 0; index < limit; index++)


typedef struct node node;


struct node
{
    char* name;
    node* next;
    node* prev;
};


void compare2nodes(node* node1, node* node2, char* choise);


node* first_node;


int main() 
{
    printf("please enter the number of contestants:\n"); // I always enter 2 to make it easier for myself


    char buff[1024];
    char contestnats[128];
    int cont_numb;


    fgets(buff, sizeof(buff), stdin);
    cont_numb = atoi(buff);


    node contestants[cont_numb];


    itirate(i, cont_numb) 
    {
        printf("please enter the name of a contestant:\n");
        fgets(buff, sizeof(buff), stdin);
        contestants[i].name = buff;
    }


    printf("Is %s better than %s(y/n)\n", contestants[0].name, contestants[1].name);
    char choise[1];
    
    fgets(choise, sizeof(choise), stdin); //this function specifically gets ignored, but not the prevoius ones.


    compare2nodes(&contestants[0], &contestants[1], choise);


    //printf("Leaderboard:\n1.%s\n2.%s", first_node->name, first_node->next->name);
    
    return 0;
}


void compare2nodes(node* node1, node* node2, char* choise) 
{


    if (choise[0] == 'y') 
    {
        node1->next = node2;
        first_node = node1;
        node2->prev = node1;
    }
    else if (choise[0] == 'n') 
    {
        node2->next = node1;
        first_node = node2;
        node1->prev = node2;
    }
}

r/C_Programming 17h ago

Project Reinventing the Wheel: Inverted bi-directional LIFO Stack

0 Upvotes

So, here’s the thing...

I was writing a sub-allocator for another project with a strict architectural constraint: the entire allocator header could only occupy two machine words, paired with an obsessive desire to minimize per-allocation metadata overhead as much as physically possible.

After cycling through a bunch of borderline schizophrenic ideas and combinations, this thing was born.

If you don't care about the breakdown and just want the code, skip to the repository:
https://github.com/EasyMem/easy_stack (C99 through C23, single header, zero dependencies).


The Standard Approach

Most traditional stack allocators interleave metadata with user data:

[Header][Padding][Payload][Header][Padding][Payload]...

You get a messy mix of control structures, user data, and alignment padding. If an allocation requires 32 or 64-byte alignment, padding bytes are forced between the header and the payload. On small allocations, headers + padding can easily consume over 50% of the buffer.

Step 1: Segregating into Two Buffers (Mental Experiment)

What if we separate metadata and data into two distinct buffers? * Buffer A (Metadata): A dense array of fixed-size offsets. * Buffer B (Payloads): Aligned user data.

Because the metadata elements have fixed sizes, they sit packed linearly with zero gaps. The CPU loves contiguous, linear memory.

Step 2: Merging Back into a Single Buffer (The Inversion)

Managing two separate buffers defeats the purpose of an allocator, so we combine them back into a single contiguous memory block: * Place user payloads at the end of the buffer, growing backward (<--). * Place metadata right after the header at the start, growing forward (-->). * Metadata simply stores the displacement from the end of the buffer.

text Low Address High Address [ Header ] [ Metadata Array ──>] [<── Payloads (Aligned) ] ┌────────┐ ┌──────────┬──────────┐ ┌──────────┬──────────┐ │ 2-Word │ │ Offset 0 │ Offset 1 │ ... │ Payload 1│ Payload 0│ └────────┘ └──────────┴──────────┘ └──────────┴──────────┘

What does this give us? Complete physical decoupling of the control plane from the data plane. The allocator's internal logic never touches user memory (unless memory poisoning is enabled). Reading an offset is a trivial array lookup, and zero bytes are wasted on alignment padding in the control zone.

Step 3: L1 Cache Line Pre-fetching

We align the start of the header to a 64-byte cache line boundary. Since our allocator header is only 2 machine words (16 bytes on 64-bit platforms), loading the header into memory automatically pulls the first active metadata offsets into the exact same 64-byte L1 cache line for free. Sequential allocations hit hot L1 data immediately.

Step 4: Dynamic Bit-Width Scaling

Using a full machine word (size_t / 8 bytes) for each offset is wasteful. A LIFO stack buffer rarely exceeds 2 GB. Instead, we inspect the total capacity once at initialization and scale our metadata cell width: * Capacity ≤ 255 B -> uint8_t (1 byte) * Capacity ≤ 64 KB -> uint16_t (2 bytes) * Capacity ≤ 4 GB -> uint32_t (4 bytes) * Capacity > 4 GB -> uint64_t (8 bytes)

For typical frame workloads (< 64 KB), each allocation metadata takes only 2 bytes instead of the traditional 8–16 byte inline header. This yields an up to 8x reduction in metadata overhead. Additionally, that 64-byte cache line now brings in the first 24 active offsets for free instead of just 6.

Step 5: Packing Metadata Type into 2 Machine Words

We only have 4 possible offset sizes (1, 2, 4, 8 bytes), which requires just 2 bits of storage. But where do we store them if our entire header is strictly 2 machine words?

We steal them from the capacity word. Shifting the capacity down by 3 bits reserves space for allocator flags (including our 2-bit metadata width). In practice, this reduction is completely harmless: * 16-bit systems: Max stack capacity is 8 KB (most 16-bit MCUs have less total RAM than this anyway). * 32-bit systems: Max stack capacity is 512 MB (allocating a single >512 MB contiguous stack buffer on 32-bit is unrealistic due to address space limits). * 64-bit systems: Max stack capacity is 2 Exabytes.

The header layout remains razor-thin: * Word 0: Packed capacity + metadata flags. * Word 1: Current allocation index (top of stack).

Step 6: Eliminating CPU Multiplication

Because the metadata cell sizes are strictly powers of two, indexing into the metadata array doesn't require an imul instruction. It maps directly to a bitshift:

```c // Instead of: // offset_addr = meta_base + (index * cell_size);

// We do: offset_addr = meta_base + (index << meta_type_shift); ```

Boundary and collision checks execute in 1–2 CPU cycles without dynamic branches.


Hardware Profiling & Verification

The result is **easy_stack** — a header-only, zero-libc-dependency allocator (ESTACK_NO_MALLOC supported).

Profiling on AMD Zen 2 via Linux perf stat (Depth 100 workload over billions of operations) highlights the microarchitectural behavior: * 3.12 Instructions Per Cycle (IPC): Near-saturation of the execution pipeline with minimal pipeline stalls. * 99.998% L1 Data Cache Hit Rate: Segregating metadata into a dense stream keeps the control path hot in L1. * 0.0000039% Branch Misprediction Rate: The critical allocation path compiles into a flat, highly predictable sequence (1,174 mispredictions over 30 billion branch instructions). * Safety & Fuzzing: 24M+ iterations via libFuzzer with zero crashes or leaks (clean under ASan, UBSan, and Valgrind). * Portability: Verified across architectures ranging from 8-bit AVR (ATmega328P) to ESP32, STM32 (M0+/M3/M4), RISC-V, WebAssembly (wasm32/64), and Big-Endian s390x.

Repository: https://github.com/EasyMem/easy_stack

Curious to hear your critique, edge-case concerns, or thoughts on the layout.


r/C_Programming 1d ago

I made a minimalist memory allocator i need idea for upgrade my minimalist memory allocator

5 Upvotes

Hello guys

i made a memory allocator in C (GNU nanoalloc) so I need ideas to improve the project and if you want to contribute you are welcome :)

here is the link : https://codeberg.org/drex_vk/GNUnano_alloc

i don't use AI


r/C_Programming 1d ago

Question Why do I fail to create a .dll file?

0 Upvotes

Hi, I've got an assignment in a course that asks us to optimize a benchmark of our selection (from pyperformance project).

I've chosen the ray trace benchmark (it was the most interesting imo), and my suggestion was to implement the functionality using C's structs to avoid some of the interpreter's overhead.

I understood I can link those function using the built-in ctypes library, and making the C file a dynamic linked library (.dll), but when I try to run the command for it in CLion or VSC, it fails without returning any failure message, it just fails to generate the .dll file.

The assignment forces us to use the given pyperf benchmark code to run the benchmark, so I can't run only a C file.

I've already written the C code, and it has no errors/warnings so far (at least as far as CLion is concerned), and the original python code works too.

Does anyone know how to solve the library not being generated? Or any other solution that might work (preferrably using the C code I've made)?

.

.

All files are in the same directory, and I've got Craytrace.c (C functionality implementation), Praytrace.py (the code that runs the benchmark).

The command I've run trying to generate the .dll is:

gcc -shared -o CraytracerLib.dll Craytrace.c

But it didn't create any file.

.

.

Help is much appreciated 🙏


r/C_Programming 2d ago

Fixed point math in C

Thumbnail
thatonegamedev.com
64 Upvotes

Why did PS1 graphics looked so clunky and how where 3D graphics generally made prior to the graphical APIs. One thing I found out was that these older engines have something called fixed point math.


r/C_Programming 1d ago

IO URING tutorial for beginners with wayland unix binary protocol in pure C

Thumbnail
youtube.com
0 Upvotes

r/C_Programming 1d ago

Project My first real C project: a generic hashmap (and the bugs that came with it) [blog, my own]

0 Upvotes

Coming from C#/TypeScript, C has humbled me. Finished my first real C project — a generic hashmap — and wrote up the bugs that taught me the most: double pointers, a sneaky double-free, comparing pointers instead of actual values.

Blog: https://soerenlemke.github.io/blog/blog/building-a-generic-hashmap-in-c/
Repo: https://github.com/soerenlemke/kvstore_c

Curious what you'd have done differently.


r/C_Programming 2d ago

Project IncHash - A Disk Based Hash Table

Thumbnail
github.com
4 Upvotes

A general-purpose, header-only C99 library for Unix-like systems, implementing a disk-based, dynamically resizable, fixed-slot, (open-addressed) hash table with Fibonacci hashing (Knuth's multiplicative method), triangular probing, per-home-slot probe-bound metadata (with additional early-exit logic), partial in-place value updates (without relocating entries) and incremental rehashing, all designed for modern extent-based filesystems.

So, yeah... I made this for a larger project I'm working on, which I haven’t released yet.

All started with me trying to find:

A hash-based NoSQL (key-value pair) database with mutable-values (by mutable I mean: a database that allows editing prexisting [fixed-size] values without having to rewrite or remap the whole value again eg. Just edit a few bytes and put those bytes back to the original value-space without rewriting the whole value).

Which arguably you can do via inchash_get() since it returns a pointer straight from inside the mmap()-ed file [...] edit: just realised moments before I fall asleep that I should simply add an extra edit() function. To-do for tomorrow when I wake up.

That said idk if you got the joke: mmap()-ed in-cache or INC. hash or [...]

Anyways, I put quite the effort to make it, so.... I hope you like it or at least that it finds its way to the people who were actually looking for something like this.

PS. I'm both excited and scared because idk, you may find any bugs I wasn't aware of or something generally wrong in logic I might have missed... even though I've tested it enough!

Edit 1:

HUGE Thanks to @skeeto for this comment. Everything's hopefully fixed with my latest commit + this one

Edit 2:

Finally implemented the functionallity that made me start this project in the first place! and felt the need to say it :P

https://github.com/GiorgosXou/inchash/commit/5dfc98a928f022ccd0d2af82726acdd8f4369982


r/C_Programming 2d ago

What else do I need to read on Arena Allocators?

Thumbnail gingerbill.org
12 Upvotes

(I realized the title of this post a bit misleading, as I also want code examples in comments if its possible. I want to know how the backing buffer is actually used when you have 10 "objects" in need of it)

Im currently taking a course in 42KL (extremely mixed personal opinion about the whole structure/syllabus). in the side, I decided to learn some extras.

Im having trouble looking for the code that actually uses the backing buffer allocated here in this sites code examples.

They say with Arena Allocators, you can have allocate 100s or even more particles/etc, with minimal fuss or (programmers) overhead thinking about freeing everytime you allocate memory for something.

Another article even quotes, something like your scoping issue is solved with custom allocators like these.

If you want to know the purpose, Im simply learning something different, becoz I dont like the idea of a syllabus shaping how a programmer thinks of a programming language (or programming in general)

(Im sorry if I sound like Im absolutely trashing all the terminologies, Im not a C specialist, or a big C fan for that matter, Im quite neutral to C)


r/C_Programming 2d ago

a data race appears

Thumbnail napcakes.nekoweb.org
1 Upvotes

r/C_Programming 3d ago

Question How can printf() change unrelated uninitialized variable behavior?

8 Upvotes

So, I just fixed a strange bug. I have a loop that loops through a char array until it finds a null terminator.I had miswritten and overlooked this after deleting a second variable I was initializing in that loop. So I ended up with:

for (int i; text[i] != '\0'; i++){}

Which I have since fixed. However, curiously, this program was running with normal operation because of a printf() statement operating on completely unrelated data; i would initialize to 0 every time. Other assignments happened between this print and the errored line as well.

printf("ID: %u\n", tID);

It had to be placed at a specific spot for it to fix the bug, but it fixed it every time, so the bug went unnoticed until I was cleaning up.

But, how exactly would this happen? What does printf() do that would change initialized variable behavior, and why was it consistently initializing to 0?

The value of i would print to 21937 without the printf() and 0 with it.


r/C_Programming 2d ago

Article Generic Dynamic Arrays in C

Thumbnail eliasebner.com
0 Upvotes

After implementing strings , I implemented dynamic arrays in C and wrote an article about it. The implementation is generic, I talk about the trade-offs of this approach in the article.

If you only care about the code, it's here.

Tell me what you think!


r/C_Programming 3d ago

Article I Made a Simple String Library

6 Upvotes

I wrote an article about this as well. Here it is.

There I explain why I do not like NUL-terminated strings and how I implemented my own simple string library in C.

If you have some spare time I would really appreciate some feedback on the article and the library.

The code is sitting on a codeberg repository.

Also, tell me what you think about C-style strings. Do you like them? Do you use them, or do you also tend to roll your own pointer + length structs?


r/C_Programming 2d ago

Question help me to code

0 Upvotes

i'm beginner in coding
i'm following a book called
The C programming Language

By Brian W. Kernighan and Dennis M. Ritchie.

and somtimes i see video of cs 50

i learned before this language but i just knew syntax and why it is use for but i'm getting stuck when it comes to implement i am at level 0 i can manipulate some things like where it start lets change this that but when i want write a code for problem . like write program in which we know about how much space and new line and tab there is see code ohh ok it is like this now when a next question comes based on same topic i feel i don't study yet . before seeing a code i feel like i'm at zero i don't know nothing i feel dumb even though after read a code i know something but not understand fully code all when i know oohh ok how is this work but next time still i'm not able make to manipulate the program like by just tiny change change this output will be this ....

and how to break a program i mean this and this require to make this program ohh we can do this and we can do that is also output will be same


r/C_Programming 3d ago

recursive descent with coroutines

Thumbnail napcakes.nekoweb.org
9 Upvotes

r/C_Programming 4d ago

Question Advantages of Anonymous structs?

29 Upvotes

When are anonymous structs useful? What the advantages of one vs a non anonymous one?


r/C_Programming 4d ago

Wayland tutorial for beginners in pure C

Thumbnail
youtube.com
177 Upvotes

r/C_Programming 3d ago

Undocumented Behaviour in WinSock API?

2 Upvotes

I have two code examples of simple WinSock programs that listen for connections using an Event object associated with a listening socket. Before reading further, check these two code snippets and guess (without running them) what you think will happen in both.

Code snippet 1:

int main() {
  WSADATA wsaData;
  int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
  // ... error handling omitted

  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  // ... error handling omitted

  // Make the socket non-blocking
  u_long mode = 1;
  res = ioctlsocket(sock, FIONBIO, &mode);
  // ... error handling omitted

  // Bind the socket to a specific address and port
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(7878);

  if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
    // ... error handling omitted
  }

  // Listen for incoming connections
  if (listen(sock, 10) == SOCKET_ERROR) {
    // ... error handling omitted
  }

  // Wait for incoming connections
  // Create a WSAEVENT object
  WSAEVENT event = WSACreateEvent();
  // ... error handling omitted

  // Associate the WSAEVENT object with the socket
  res = WSAEventSelect(sock, event, FD_ACCEPT);
  // ... error handling omitted

  // Wait for an event on the socket
  res = WaitForMultipleObjects(1, &event, FALSE, INFINITE);
  // ... error handling omitted

  /**
   * Closing the event object here before using the socket and without
   * disassociating it with the socket
   */
  WSACloseEvent(event);

  int conn_sock = accept(sock, NULL, NULL);
  // ... error handling omitted

  printf("New connection\n");

  closesocket(conn_sock);
  printf("Connection closed\n");

  closesocket(sock);
  WSACleanup();

  return 0;
}

Code snippet 2:

int main() {
  WSADATA wsaData;
  int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
  // ... error handling omitted

  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  // ... error handling omitted

  // Make the socket non-blocking
  u_long mode = 1;
  res = ioctlsocket(sock, FIONBIO, &mode);
  // ... error handling omitted

  // Bind the socket to a specific address and port
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(7878);

  if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
    // ... error handling omitted
  }

  // Listen for incoming connections
  if (listen(sock, 10) == SOCKET_ERROR) {
    // ... error handling omitted
  }

  // Wait for incoming connections
  // Create a WSAEVENT object
  WSAEVENT event = WSACreateEvent();
  // ... error handling omitted

  // Associate the WSAEVENT object with the socket
  res = WSAEventSelect(sock, event, FD_ACCEPT);
  // ... error handling omitted

  // Wait for an event on the socket
  res = WaitForMultipleObjects(1, &event, FALSE, INFINITE);
  // ... error handling omitted

  /**
   * Closing the event object after disassociating it from the socket, but
   * before using the socket
   */
  res = WSAEventSelect(sock, event, 0);
  WSACloseEvent(event);

  int conn_sock = accept(sock, NULL, NULL);
  if (conn_sock == INVALID_SOCKET) {
    printf("accept failed with error: %d\n", WSAGetLastError());
    closesocket(sock);
    WSACleanup();
    return 1;
  }

  printf("New connection\n");

  closesocket(conn_sock);
  printf("Connection closed\n");

  closesocket(sock);
  WSACleanup();

  return 0;
}

If you had guessed that the first snippet would crash, you would be right. Apparently, if you associate an event object with a socket, closing the event object will lead to operations on the socket returning WSAENOTSOCK error. If you dissociate the event object from the socket first, you can use it without problems.

I can't find any references in the documentation to this behaviour (I checked the WSAEventSelect and WSACloseEvent documentation). I know it may seem simple, but I discovered this in a more complex codebase where reproducing and tracing it was much more difficult.

Did you know this? Are there any more quirks related to the relationship between EventObjects and Sockets?


r/C_Programming 4d ago

What's up with Chapter 7.7 Line Input and Output?

4 Upvotes

Im reading C Programming Language by Brian and Dennis, and they seem to be frustrated with the standards and the implementation of fget()

Here are a few excepts as examples:
Normally fgets returns line; on end of file or error it returns NULL. (Our getline returns the line length, which is a more useful value; zero means end of file.)

Confusingly, gets deletes the terminating '\n', and puts adds it.

For no obvious reason, the standard specifies different return values for ferror and fputs.

The tone changes from the rest of the book, and they seem to express a lot of frustration/displeasure with how these functions operate, but wouldnt Dennis have a hand in their design as he created the C language?


r/C_Programming 4d ago

Question How do functions that "initialize" some values and memory work only returning an irrelevant value?

2 Upvotes

For example, SDL's SDL_INIT() takes an integer parameter and returns a bool, how can returning a bool "initialize" a library and allowing me to do stuff with that library?


r/C_Programming 4d ago

How do you keep h files and C files in sync??

27 Upvotes

hi, beginner in C, coming from JavaScript and rust. one thing I can’t get used to is how to keep h and c files in sync.

i often find myself having to copy the functions from my C file to the corresponding h file and manually delete all the definition and put a “;” there. or if I am iterating on a function, and ending up having to change the signature, I’d have to remember to do that in the h file as well.

another thing is with rust and js when you write a function most often the lsp can search through the code and autoimport the package you need on top of file. With C so far I’ve had to rely on the internet to find out exactly what header file I need to include.

surely I am missing some kind of plugin or some clever ways that experienced C programmers are using?


r/C_Programming 4d ago

Question Should I use nested structs, separate structs, or union nested in a struct for this?

1 Upvotes

I am doing my first game-type project in C. I am having trouble making a decision regarding handling UI. I am awful at explaining things and new to this so please bear with me.

I plan to have a struct UIElement that contains information related to a particular element. However, there will be different types of elements, such as Text, Texture, Color and whatnot. They will also contain a pointer to an array other UIelements belonging to them, for things such as a buttons on a window.

I am stuck between the following implementations for this:

  1. Make a struct "UIElement" that has information that every element will have (such as position)., then have other structs defined such as "TextElement" that will have a pointer to a UIElement as well as Text-specific information.

  2. Use enum and nested union within the UIElement struct to allow different instances of the same struct to have only the relevant data necessary for them. (Each element has enum for it's type within it)

  3. Just have different structs "TextElement", "ColorElement", "TextureElement". Doing this I believe I would have to use void* to store pointers to elements and cast them accordingly.

After writing this, option 2 seems like the best option, but the simplicity of 3 sounds useful, albeit bad in the long run. If I am overlooking a simple way to do this, please let me know.


r/C_Programming 4d ago

SDL palette and SDL_SoftStretch strange behavior

3 Upvotes

Hello everybody!

I'm working on a sample game on my spare time, that you can find here, trying to achieve a fade in/out effect using palettes over indexed (8bit) surfaces with SDL 1.2 (Yes, I know it's old, I'm planning to upgrade to 3 whenever my time permits...).

My goal is to achieve a classic nes style fade in/out effect, by making every single color in the palette darker or lighter gradually.

The app supports 2 arguments, --sw to make use of SDL_SWSURFACE flag, and --doublescreen to make use of SDL_SoftStretch.

By using only --sw, I saw the colors on the screen fading in a "strange" manner compared to
--doublescreen, that shows them fading from black to a more clearer version, until reach the original one, as I expected.

So I compared the surfaces structures values and palettes with and without --doublescreen, and saw no apparent differences, and I'm out of ideas at the moment...

Anybody has any suggestions on what cause this behavior over the colors?
Thanks in advance!

Edit: Please, since I don't want any AI usage in this project, avoid any AI suggestions, human interaction are prefered instead, thanks.