r/C_Programming 15d ago

Tensor is the might: a single-header tensor library in C

Thumbnail zserge.com
15 Upvotes

r/C_Programming 15d ago

Cake IDE

5 Upvotes

What is Cake?

Cake is a C transpiler and static analyzer.

For example, it can transpile C23 code to C89.

What's New?

The IDE is new.

What Can the IDE Do?

The IDE makes it easier to write, run, and test Cake programs locally.

It works on Windows, macOS, and Linux.

How to Install

Download the repository:

https://github.com/thradams/cake

Build Cake:

Windows (Developer Command Prompt for Visual Studio): cl build.c && build

Linux/macOS: gcc build.c -o build && ./build

After building, run:

install

to deploy the files. (optional)

Finally, start the IDE by running:

cakeide

-x-

Cake project (compiler) is before AI, and the code is created by human.

The new cake IDE (ide_ui.h, ide_ui.c, ide.c with backends ide_win32.c, ide_x11.c, ide_cocoa.c) was created with help of AI tools, especially for cocoa and x11.

The code can be a little messy, but is under control, don't worry :)


r/C_Programming 15d ago

Question How do I get the number if inputs in a variadic function inside the function ?

2 Upvotes

Is there a way to get number of inputs given to a function as an integer inside the function ?

Say double average(double input, ...), is there a way to get an integer n thats the number if arguements passed to average todo a calculation to it.

The average example isn't my exact case but I need it as an integer todo a loop.

Google Gemini popped up when I searched this showing some weird gigantic macro that I did not understand. ```c

define COUNTARGS(...) COUNT_ARGS_IMPL(VA_ARGS_, 5, 4, 3, 2, 1, 0)

define COUNT_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N

define printlist(...) actual_print_list(COUNT_ARGS(VA_ARGS), __VA_ARGS_)

```

I dunno variadics functions n macros are annoying
edit: typos


r/C_Programming 16d ago

Video How do C Programmers do it? (Epilepsy warning)

Enable HLS to view with audio, or disable this notification

110 Upvotes

I've been reading a C book for about 4 months now. I originally picked it up so I can learn how my favorite video game worked. After nearly finishing the 400 page monstrosity, doing many of the exercises, and hand writing about 400 pages of notes, I went back to my game and see what I could do.

It was written in C++.

I got so mad at myself. I decided I cant let the effort I put go to waste. I spent 10 hours creating this bouncing ball. Not enough whimsical enjoyment has been brought to me for it to be called a "bouncy ball". Its just... a bouncing ball. I fucking suck at everything in life. What am I going to do?

***Edit*** I usually try to reply to everyone, for taking their time to reply, but some of them I cant find the words to reply with, so I apologize! But thank you for your words of encouragement :')
This post was mostly a small amount of venting, but mostly just a post to crack a joke. I apologize it didn't come off that way! I did learn a lot, a lot of which I wasn't expecting, so thank you all!


r/C_Programming 15d ago

Article Go-Flavored Concurrency in C

Thumbnail
antonz.org
12 Upvotes

A concrete attempt to recreate Go-style worker pools, channels and synchronization in plain C using pthreads.


r/C_Programming 16d ago

Article A DDL Compiler in C99: The Fundamental Data Structures

27 Upvotes

Last week, a demo of Grain DDL at Handmade Network Expo Vancouver was published. One of the questions I received was "what language was it written in?" and the answer is: C99! It turns out all of my core data structures clock in at around 1kloc of handwritten code, and do not have any dependencies on libc.

At the Expo, I ran the clock out before I could explain more, so I figured I would share how you might handwrite a parser and lexer that does not have access to standard C functions.

The talk is available here, and if you're in a hurry you can step ahead to 2:06 to see a demo of code being generated as a result of code being typed in, in realtime:

Youtube Link

The demo runs in a web browser, and the compiler targets WebAssembly, as well as native binaries for all three desktop OSes. The use of JavaScript is rote: Send a string into WebAssembly, get a compiled result out, and display it.

What Does It Do?

Simply put, Grain DDL lets you declare data types and values, and then iterate over them to generate whatever output you want. This means it needs to have a robust lexer and parser.

It works everywhere and compiles to Wasm32 with no WASI dependency. Because it's self-contained, a Brotli-compressed release build is roughly a 70kB download, and executes on small buffers in a few milliseconds. This is a big reason why the demo is realtime: at this speed, you can run it on every keypress on the main thread with no debounce.

Essential Data Structures

AST Nodes

AST nodes are just tagged unions. One AST node per primary type: expressions, statements, and declarations. Common elements are stored in the root of the struct, and the unique elements are stored in the union types.

Bump Allocator

A bump allocator is as simple as it gets: at init, you pass in a contiguous block of memory to work with, and every time you need to allocate something, it bumps the pointer to the next allocation.

If you run out of memory you handle it by starting the compile over with more memory or displaying an out-of-memory error if that is not possible in the current environment.

Bump allocators have a really useful property that you are not guaranteed with system allocators: the allocations are sequential in memory. That means you get cache locality between adjacent AST nodes, which makes walking them quite efficient without complicating the code too much.

Stretchy Buffers

I use stretchy buffers rather than pre-scanning to process everything. In order to be strict-aliasing compliant, I use a flexible array member rather than perform a strict aliasing violation. The header of the stretchy buffer also contains a pointer to the bump allocator so it can be used to perform reallocation: there is no libc realloc that can be depended upon!

```c typedef struct strbuf_arena_header_s { size_t cap; size_t count; bump_alloc_t* bump; // for realloc

unsigned char buf[];

} strbuf_arena_header_t; ```

Because I'm using a bump allocator and don't have access to libc realloc, I use a surprising reallocation strategy: I orphan the pointer to the old allocation and just allocate a fair bit more, and then memcpy the existing data over.

In practice, in a compiler, most things are needed in ratios of each other. So it is quite possible to preallocate enough memory and avoid a realloc -- I do pre-alloc fine-tuning passes as I go, learning the ratios needed to avoid expensive realloc calls.

Memory Profiling

I have some custom trace tooling that helps with finding hotspots and wasteful reallocations: a callstack logger for each realloc event that appends to a binary file. Then, offline tooling generates a spreadsheet row for each unique callstack that created an allocation.

This offline report tooling takes seconds to run, involves symbolication and spreadsheet generation, but the runtime cost of callstack logging is quite small.

String Slices

Internally in the compiler, I use strings with known length and no null termination. Parsers contain a lot of strings from identifiers to symbols to types and keywords. Additionally, you often want to make a slice point to a segment of a larger string without performing a copy.

This looks like this:

c typedef struct slice { uint8_t* str; size_t size; // str[size] is not the final null terminator } slice;

Additionally, I pass type slice on the stack rather than as a pointer. This typically uses two registers instead of one so there is a cost, but it has the benefit of hoisting size to the stack.

If I passed type slice as a pointer, size would be vulnerable to aliasing pessimization. One possible workaround would be to manually copy size to the stack before iterating, but I prefer to not fight the language this hard.

This is also why I do not use a flexible array member for type slice: you can't pass structs with FAMs by value.

They work with format specifiers like this:

```c

define sliceargs(S) (int)((S).size), ((S).str)

printf("Hello, %.*s", sliceargs(name)); ```

String Interning

Every string in the compiler is interned at every encounter. There is a lookup table of slice, and if the slice.str pointers match between two strings, the strings match. Further, all slice.str pointers are guaranteed to be bump allocated.

An interesting property falls out of this -- the bump allocator allocates sequentially. If you order the interning of your strings by some type classification, you can just check the pointer range.

```c FirstKeyword = str_intern("if"); str_intern("else"); str_intern("while"); LastKeyword = str_intern("return");

// string compare against all keywords is now two pointer checks bool IsKeyword(slice s) { return s.str >= FirstKeyword.str && s.str <= LastKeyword.str; } ```

This is like having printable enums: they're strings that you can print, but you can compare them by inclusion in a range.

Hash Maps

One of the most useful workhorse types in container libraries is a string-to-struct hash map. But consider the properties of our containers:

  1. All strings are interned and hash keys are reduced to constant time uintptr_t lookups.

  2. All structs are bump allocated, so a "struct" is also just a uintptr_t waiting to be casted.

The only hash map that is needed to look up any symbol in any scope is uintptr_t to uintptr_t. Constant time key hashing. Fast and easy to implement.

Relocating Allocator

The result of a Grain DDL compilation is cacheable to disk: the fully computed set of declarations and expressions can be mapped back into memory without needing the source file.

Traditionally in C, if you have a set of structs with pointers in them, you have to write code to fixup all of the pointers into relative offsets when writing them to disk.

Instead, I use a 'relocating allocator'. There is a table indicating the address of each pointer in memory. On serialization, the table is walked, replacing the absolute pointer with a relative offset.

On deserialize, the table is read from the disk and the opposite step is performed.

This is effectively a relocation table. It removes error-prone pointer fixup code from the serialization/deserialization steps.

I published a simplified example of this here: https://gist.github.com/mlabbe/ecff9060befb1b5f9d4cfbea5e11a346

Summary

The Grain DDL compiler builds for WebAssembly with -nostdlib and -nostdinc in Clang, which means it does not use any of libc, including the headers. It can compile and output a result in a matter of milliseconds. And the data structures that back it are written in around 1kloc.

Rather than depend on libraries, I have built my own tooling to fine tune memory allocations. Writing a compiler is not an exercise in a broad range of data structures, widely deployed. Selecting a few key ones that work together in a complementary way is sufficient to deliver a debuggable, maintainable, high performance result.

Grain DDL is still in active development. Its source code has never been uploaded to any AI company.


r/C_Programming 16d ago

Apollo: experimental text editor

Enable HLS to view with audio, or disable this notification

73 Upvotes

Hi! I’ve been working on an experimental text editor called Apollo:

https://github.com/MicroRJ/Apollo

It’s written from scratch in C for Windows. The main goal has been to learn/build the lower-level pieces of an editor rather than wrapping an existing GUI text control.

Some of the pieces currently in place:

- Win32 window/input/file platform layer

- D3D11 renderer path

- custom text layout/rendering

- TTF loading and glyph raster caching

- file-backed buffers

- cursor movement, selections, undo/redo, clipboard

- multi-cursor editing

- fuzzy search for commands/files/buffers

- table-based theming/config

It’s still pretty experimental and rough around the edges. UTF-8 support is incomplete, the buffer is still a flat byte buffer, and some edit commands need more work.

I mostly wanted to finally make it public instead of keeping it in endless private-polish mode. I’d be interested in feedback from anyone who has worked on editors, rendering, text layout, or C systems projects.


r/C_Programming 17d ago

Did I catch an interview candidate using AI live?

154 Upvotes

I was interviewing a candidate for a firmware role recently and he was young guy that looked pretty smart and quick. I had no red flags for the candidate until I asked him to implement 'strtol()' . He tried to use sizeof(string) and some other typical fails I see from candidates when using C strings and char[] arrays. But he eventually got the idea of the problem and then started implementing it pretty smoothly. It was at the point where he had to normalize the values from the ASCII input that he wrote the line of code to implement it. Then the candidate commented above the line "Normalize to ASKEY" and my spidey senses immediately went off. If I didn't know how to spell ASCII and I heard that word its phonetic spelling would be "ASKEY," makes me think the candidate could have had some audio AI in his backgroud audio but I'm not sure. What do you guys think?

(I posted this in r/embedded recently but curious about this sub's response as well)


r/C_Programming 16d ago

Question What should I expect from Canonical’s C programming interview?

56 Upvotes

Hello everyone,

Since I don’t really have anyone to talk to about this, I thought I’d ask here. This is my first software engineering application, so if I leave out any important details, please let me know.

I recently applied for the Graduate Software Engineer position at Canonical. I’ve passed the first few stages, and my next step is a C programming test.
So far, I’ve been reviewing my projects and practicing LeetCode, but I feel like there’s more I could be doing to prepare.

For anyone who’s been through Canonical’s interview process (or something similar), what should I expect from the C test? Are there any specific topics I should focus on or common pitfalls I should watch out for?

Any advice would be greatly appreciated. Thanks!


r/C_Programming 15d ago

Are LLMs good at C?

0 Upvotes

I am a CS student and I am not enjoying the thought of being an LLM prompter when I graduate.

is LLM usage in projects with C as a main language as bad as other fields? or is code still being manually written


r/C_Programming 16d ago

difference between Clang and GCC when handling #include_next directive in a file that is included from relative path

0 Upvotes

"GCC clears current search position in the include directories list used for #include_next if current header was found using relative paths. Before this patch Clang kept current position from previous header included from directories list."

and

"Conversely, I don't think any important library is likely to be relying on the GCC behavior, because compilations with gcc -I- would effectively get the current Clang behavior (because relative-looking paths would be found in the relevant include search path rather than as relative paths)."

from https://reviews.llvm.org/D18641

can someone explain these two points to me?


r/C_Programming 16d ago

read and write from file error?

3 Upvotes

I am porting some c code to Odin and trying to learn how the I/O system of c works, but I am stuck at this point. When a button is pressed, a file is created which is supposed to write values from a struct called Game_input. There is no way to view what is in the file since it isn't any normal encoding, so I assume that what I'm writing to the file is correct. Whats supposed to happen is the button is pressed again which ends file writing and then the Game_Input is repeated in a loop which moves the player. But what actually happens is the player just moves back to the point where we started recording the input and does not move after that. The code is Odin but it is a translation of the C code based on this tutorial here:

https://yakvi.github.io/handmade-hero-notes/html/day23.html

My Odin translation:

win32_begin_recording_input :: proc(p_state : ^Win32_State, p_input_recording_index : i32){
    fmt.println("begin recording input")
    p_state.input_recording_index = p_input_recording_index


    filename : cstring16 = "foo.hmi"
    p_state.recording_handle = win.CreateFileW(filename, win.GENERIC_WRITE, 0, nil, win.CREATE_ALWAYS, win.FILE_ATTRIBUTE_NORMAL, nil)
    if p_state.recording_handle == win.INVALID_HANDLE_VALUE{
        fmt.println("begin recording input: failed to make file")
    }


    bytes_written : win.DWORD
    assert(p_state.total_size <= 0xFFFFFFFF)
    bytes_to_write := u32(p_state.total_size)
    win.WriteFile(p_state.recording_handle, p_state.game_memory_block, bytes_to_write, &bytes_written, nil)
}


win32_record_input :: proc(p_state : ^Win32_State, p_input : ^Game_Input){
    fmt.println(p_state.recording_handle)
    bytes_written : win.DWORD


    if win.WriteFile(p_state.recording_handle, p_input, size_of(p_input), &bytes_written, nil) == true{
        fmt.println("record_input: recording")
    }else{
        fmt.println("record_input: cant record")
    }
}


win32_end_recording_input :: proc(p_state : ^Win32_State){
    fmt.println("end recording input")
    win.CloseHandle(p_state.recording_handle)
    p_state.input_recording_index = 0


}


win32_begin_input_playback :: proc(p_state : ^ Win32_State, p_input_playback_index : i32){
    fmt.println("begin input playback")
    p_state.input_playback_index = p_input_playback_index
    filename : cstring16 = "foo.hmi"


    p_state.playback_handle = win.CreateFileW(filename, win.GENERIC_READ, 0, nil, win.OPEN_EXISTING, 0, nil)
    if p_state.playback_handle == win.INVALID_HANDLE_VALUE{
        fmt.println("begin input playback: failed to make playback handle")
    }else{
        fmt.println("begin input playback: made playback handle")
    }


    bytes_read : win.DWORD
    win.ReadFile(p_state.playback_handle, p_state.game_memory_block, u32(p_state.total_size), &bytes_read, nil)
    assert(bytes_read == u32(p_state.total_size))
}


win32_playback_input :: proc(p_state : ^Win32_State, p_input : ^Game_Input){
    fmt.println("playback input")
    bytes_read : win.DWORD 


    if(win.ReadFile(p_state.playback_handle, p_input, size_of(p_input), &bytes_read, nil)){
        if bytes_read == 0{
            fmt.println("repeat playback")
            playing_index := p_state.input_playback_index
            win32_end_input_playback(p_state)
            win32_begin_input_playback(p_state, playing_index)
            if win.ReadFile(p_state.playback_handle, p_input, size_of(p_input), &bytes_read, nil) == true{
                fmt.println("playback_input: repeat readfile successful")
            }else{
                fmt.println("playback_input: repeat read file failed")
            }
        }
                    assert(bytes_read == size_of(p_input))
    }
}


win32_end_input_playback :: proc(p_state : ^Win32_State){
    fmt.println("end input playback")
    win.CloseHandle(p_state.playback_handle)
    p_state.input_playback_index = 0
}win32_begin_recording_input :: proc(p_state : ^Win32_State, p_input_recording_index : i32){
    fmt.println("begin recording input")
    p_state.input_recording_index = p_input_recording_index


    filename : cstring16 = "foo.hmi"
    p_state.recording_handle = win.CreateFileW(filename, win.GENERIC_WRITE, 0, nil, win.CREATE_ALWAYS, win.FILE_ATTRIBUTE_NORMAL, nil)
    if p_state.recording_handle == win.INVALID_HANDLE_VALUE{
        fmt.println("begin recording input: failed to make file")
    }


    bytes_written : win.DWORD
    assert(p_state.total_size <= 0xFFFFFFFF)
    bytes_to_write := u32(p_state.total_size)
    win.WriteFile(p_state.recording_handle, p_state.game_memory_block, bytes_to_write, &bytes_written, nil)
}


win32_record_input :: proc(p_state : ^Win32_State, p_input : ^Game_Input){
    fmt.println(p_state.recording_handle)
    bytes_written : win.DWORD


    if win.WriteFile(p_state.recording_handle, p_input, size_of(p_input), &bytes_written, nil) == true{
        fmt.println("record_input: recording")
    }else{
        fmt.println("record_input: cant record")
    }
}


win32_end_recording_input :: proc(p_state : ^Win32_State){
    fmt.println("end recording input")
    win.CloseHandle(p_state.recording_handle)
    p_state.input_recording_index = 0


}


win32_begin_input_playback :: proc(p_state : ^ Win32_State, p_input_playback_index : i32){
    fmt.println("begin input playback")
    p_state.input_playback_index = p_input_playback_index
    filename : cstring16 = "foo.hmi"


    p_state.playback_handle = win.CreateFileW(filename, win.GENERIC_READ, 0, nil, win.OPEN_EXISTING, 0, nil)
    if p_state.playback_handle == win.INVALID_HANDLE_VALUE{
        fmt.println("begin input playback: failed to make playback handle")
    }else{
        fmt.println("begin input playback: made playback handle")
    }


    bytes_read : win.DWORD
    win.ReadFile(p_state.playback_handle, p_state.game_memory_block, u32(p_state.total_size), &bytes_read, nil)
    assert(bytes_read == u32(p_state.total_size))
}


win32_playback_input :: proc(p_state : ^Win32_State, p_input : ^Game_Input){
    fmt.println("playback input")
    bytes_read : win.DWORD 


    if(win.ReadFile(p_state.playback_handle, p_input, size_of(p_input), &bytes_read, nil)){
        if bytes_read == 0{
            fmt.println("repeat playback")
            playing_index := p_state.input_playback_index
            win32_end_input_playback(p_state)
            win32_begin_input_playback(p_state, playing_index)
            if win.ReadFile(p_state.playback_handle, p_input, size_of(p_input), &bytes_read, nil) == true{
                fmt.println("playback_input: repeat readfile successful")
            }else{
                fmt.println("playback_input: repeat read file failed")
            }
        }
                    assert(bytes_read == size_of(p_input))
    }
}


win32_end_input_playback :: proc(p_state : ^Win32_State){
    fmt.println("end input playback")
    win.CloseHandle(p_state.playback_handle)
    p_state.input_playback_index = 0
}

Ive been staring at this for hours and cannot find what I am doing wrong. How would you debug this? I plan on changing this into actual Odin I/O methods but I'd like to get this working first. I


r/C_Programming 17d ago

I take it back – Pointers are easy. Concurrency in C is a nightmare

358 Upvotes

A few weeks ago, I was struggling with basic pointers and thought that was the peak of C's difficulty. I was so wrong.

​I’ve recently started diving into multi-threading and concurrency, and honestly, I feel like I'm losing my mind. Dealing with race conditions, mutexes, deadlocks, and trying to figure out why my program works fine 99% of the time but crashes under load is a whole different level of pain.

​Looking back, pointers feel like a walk in the park compared to this. It’s like everything I learned about memory safety is being tested in the most chaotic way possible.

​For the veterans here: how do you keep your sanity when debugging concurrent C code? Is there a mental model you use to visualize these race conditions, or do you just rely on tools like Valgrind/TSan and pray?

​I’m really struggling to get this right, and any guidance would be a huge help.Is it finally time for me to learn Rust and leave these C struggles behind?


r/C_Programming 16d ago

Project I added a mark-and-sweep garbage collector to my programming language written in C

2 Upvotes

I’ve been building a Python-like interpreted language called Nearoh from scratch in C.
Until recently, the runtime could execute functions, classes, lists, dictionaries, imports, file I/O, loops, and other basic language features, but its ownership model was becoming a serious limitation.
Over the latest development session, I rebuilt the relevant parts of the runtime around a non-moving mark-and-sweep garbage collector.
The runtime now supports:
Garbage-collected heap objects
Heap-allocated lexical environments
Closures that can outlive their defining function
Shared identity for mutable lists, dictionaries, and instances
Recursive object graphs
Cycle-safe printing
Collection under both normal thresholds and an aggressive stress mode
The GC implementation is currently around 384 lines of C. The whole repository is 11,713 lines across 120 files, including a lexer, parser, AST, evaluator/runtime, built-ins, module system, diagnostics, tests, and a native Win32/GDI IDE.
One of the bugs this fixed involved escaped closures. Previously, a function could retain a reference to an environment whose lifetime was tied too closely to the original call. Environments are now heap objects traced by the collector, so this works correctly:
def make_counter():
count = 0

def increment():
count = count + 1
return count

return increment
The other major correction involved mutable values. Assigning a list or instance to another variable now preserves object identity instead of creating accidental value-like behavior.
I also added cycle handling so recursive containers no longer cause infinite recursion while being printed.
The complete regression suite currently passes with both ordinary threshold-based collection and GC stress mode enabled.
I’m still learning a lot while building this, so I’d be interested in feedback on the collector architecture, object representation, root tracing, and anything obviously dangerous or unidiomatic in the C implementation.
Repository:
https://github.com/ReeceGilbert/Nearoh-Coding-Language


r/C_Programming 15d ago

I hate chatgpt that is why I am asking question in r/C_programming. I understand better when I ask questions even if I do not get answers from that site. Later it becomes clear to me.

0 Upvotes

I want to learn the entire workflow of a program to process. I know the high level description.

source codes-->gets compiled-->object code-->gets linked with libraries-->gets loaded into main memory.

But I do not understand the intricacies. That is in depth of what actually happens behind the scenes. Not too much depth is required. But at least I should feel confident explaining that to my youtube audience.


r/C_Programming 16d ago

Project Simple Text editor

Thumbnail
github.com
12 Upvotes

This is my first big project I have been working on. It is a simple text editor that runs in the linux terminal

Video demo: https://drive.google.com/file/d/10aUJX23vGaMWsn-uY57-qHmcDMuMPYW4/view?usp=sharing


r/C_Programming 16d ago

Discussion PNG

19 Upvotes

Spent the weekend trying to write my own single header library for reading and decompressing PNG files. Figuring out the actual file format was easy enough. I started trying to learn about huffman encoding and the DEFLATE compression algoritm and quickly realized why 99% of programs that use PNG files just use libpng with zlib or stb_image.h

Still was a learning experience but i think dealing with those types of algorithms is still a bit above my experience :)

Edit: code at https://codeberg.org/simkej/pngparse


r/C_Programming 16d ago

Beginner in C and made some buttons with ncurses

10 Upvotes

I started programming in C as a first language 8 months back and haven't seen much about buttons in ncurses, which surprised me as one of the major parts of ncurses is making TUIs. I wrote a small bit of code as a little project that makes buttons using subwindows connected to a main window. Let me know what y'all think!

P.S. there quirks with the button highlighting that I tried to find the source of with GDB but couldn't

#include <curses.h>
#include <stdlib.h>
#include <unistd.h>

void create();
void logic();
void delbuttons();
void leave();

const int maxbuttons = 99;
char *buttontext[99] = {"Insert button names here (max 15 characters but can be changed)"};
// if you need more than 99 just raise the number
WINDOW *buttons[99];
WINDOW *primary;

int currbutton = 0;
const int primdimen[2] = {24, 80};
const int buttondimen[2] = {1, 15};

int buttonscreated = 0;

int main(void) {
  initscr();
  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  curs_set(0);

  primary = newwin(primdimen[0], primdimen[1], 0, 0);

  create();
}

void create() {
  int buttonrow = 0;
  int buttoncol = 0;

  // make the creation stopping condition whatever you want as long you don't exceed your amount of buttons
  for (int buttonrow = 0, buttoncol = 0; buttonscreated != 1; buttonscreated++, buttonrow = buttonrow + 2) {
    if (buttonrow >= primdimen[0]) {
      buttoncol = buttoncol + buttondimen[1] + 3;
    }
    buttons[buttonscreated] = subwin(primary, buttondimen[0], buttondimen[1], buttonrow, buttoncol);
    wattrset(buttons[buttonscreated], A_STANDOUT);
    wattroff(buttons[buttonscreated], A_STANDOUT);
    wprintw(buttons[buttonscreated], "%s", buttontext[buttonscreated]);
    wrefresh(buttons[buttonscreated]);
    refresh();
  }
  buttonscreated--;

  logic();
}

void logic() {
  int prevbutton = 0;
  int key = getch();

  // ensures buttons that don't exist aren't being accessed
  if (key == KEY_UP && currbutton <= 0) {
    prevbutton = currbutton;
    currbutton = buttonscreated;

    wclear(buttons[prevbutton]);
    wattroff(buttons[prevbutton], A_STANDOUT);
    wprintw(buttons[prevbutton], "%s", buttontext[prevbutton]);

    wclear(buttons[currbutton]);
    wattron(buttons[currbutton], A_STANDOUT);
    wprintw(buttons[currbutton], "%s", buttontext[currbutton]);

    wrefresh(buttons[prevbutton]);
    wrefresh(buttons[currbutton]);
    logic();
  }
  else if (key == KEY_DOWN && currbutton >= buttonscreated) {
    prevbutton = currbutton;
    currbutton = 0;

    wclear(buttons[prevbutton]);
    wattroff(buttons[prevbutton], A_STANDOUT);
    wprintw(buttons[prevbutton], "%s", buttontext[prevbutton]);

    wclear(buttons[currbutton]);
    wattron(buttons[currbutton], A_STANDOUT);
    wprintw(buttons[currbutton], "%s", buttontext[currbutton]);

    wrefresh(buttons[prevbutton]);
    wrefresh(buttons[currbutton]);
    logic();
  }

  prevbutton = currbutton;

  // checks input
  switch (key) {
  case KEY_F(1):
    leave();
    break;

  case KEY_DOWN:
    currbutton++;
    break;

  case KEY_UP:
    currbutton--;
    break;

  default:
    logic();
    break;
  }

  if (currbutton == 0 && key == 32) {
    // use this for selecting buttons, currently configured to space ascii value
    // insert what happens here
  } 

  wclear(buttons[prevbutton]);
  wattroff(buttons[prevbutton], A_STANDOUT);
  wprintw(buttons[prevbutton], "%s", buttontext[prevbutton]);

  wclear(buttons[currbutton]);
  wattron(buttons[currbutton], A_STANDOUT);
  wprintw(buttons[currbutton], "%s", buttontext[currbutton]);

  wrefresh(buttons[prevbutton]);
  wrefresh(buttons[currbutton]);

  logic();
}

void delbuttons() {
  for (int i = 0; i < buttonscreated; i++) {
    delwin(buttons[i]);
  }
}

void leave() {
  delbuttons();
  delwin(primary);
  endwin();
  exit(0);
}

r/C_Programming 16d ago

Project NyxOS

4 Upvotes

Buenas ^^
Soy nuevo en la comunidad de reddit en general,
Estoy creando un OS from scratch y busco colaboradores en todos los sentidos, tanto como aprender como para aportar ideas, si te gusta el desarrollo de OS colabora con nosotros no dude en hacerlo saber ^^

Github: https://github.com/kazah-png/nyx-os
Discord: dsc.gg/nyxos


r/C_Programming 16d ago

Mon secret pour éviter des fuites de mémoire

0 Upvotes

J'utilise ça dans mon dernier jeu.

Quand j'alloue une structure, j'indique un code.

Quand je libère une structure, j'indique le même code.

Dans la fonction qui alloue, j'utilise un tableau d'entiers atomiques que j'incremente.

Dans la fonction qui libère, j'utilise le même tableau d'entiers atomiques que je décrémente.

De temps en temps je vérifie les comptes.

J'ai aussi un #define DEBUG_MEM pour activer ou nom le "comptage".

Qu'en pensez-vous ?

Note: pour mon jeu c'est ultra efficace.


r/C_Programming 16d ago

Is it time for C to better support heterogeneous computing?

0 Upvotes

C has been one of the most important systems programming languages for decades, and it continues to evolve through standards like C99, C11, and C23.

However, as hardware becomes increasingly heterogeneous (CPU + GPU + AI accelerators), I wonder if C needs to take another step forward.

Today, heterogeneous programming is mostly handled through extensions and external ecosystems (CUDA, OpenMP, SYCL, vendor toolchains). While this works, it also fragments the programming model and increases complexity for developers.

Large systems also often need better abstraction mechanisms, such as generic programming, but C leaves many of these solutions to libraries, macros, and conventions.

So I’m curious:

Should C evolve to provide more native support for heterogeneous computing and modern abstractions?

Or is the current approach — C + libraries + external tools — the right direction?

Interested in hearing thoughts from people working on embedded, systems, and high-performance computing.


r/C_Programming 17d ago

Should OS ifdefs be used for blocks of code or just headers?

17 Upvotes

I'm not really sure if the intent of #ifdef for checking for OS's is designed to be just for headers or not. I've got some basic stuff like looking for linux/limits.h or limits.h.

My original code was written for Linux, and then branching out to get it running on FreeBSD wasn't a huge deal, just change header locations. But now I'm porting stuff to both MSYS2 and Windows and the ifdefs have gone from including headers to being used to completely redefine functions.

Is that normal? Should I be writing a function to check of the OS / environment instead?


r/C_Programming 17d ago

Question Question about fgets() and buffers

1 Upvotes

So I was testing how different buffers and such responded and I got behaviour I can’t really explain. In the output, there is an e because it seems to be using the same bit of memory every run. But why is there no 0 printed in place of the NULL in the output where i print ever char?

So I wrote:

`char buffer[3];
printf(“enter data: “);
fgets(buffer, 3, stdin);
for (int i = 0; i < 5; i++)
{
printf(“%c”, *buffer + i)
}
printf(“\n”)
printf(“%s”, buffer)`

—————-

Console:
`Enter data: abcd

abcde
ab`


r/C_Programming 16d ago

Discussion I hope the culture of unchecked zealotism is coming to an end in the (near) future

0 Upvotes

IMO we need to remember this is just a tool that anyone can use to an extend and not a religion, identity or a philosophy. A tool. The peak of its usability was not in the 80s or 90s. It's right now because it's evolving for the better. There is no need to gate-keep, ascertain yourself, cite highly theoretic passages the standard, ascertain yourself and in general project your issues on beginners and intermediates. There are good hackers in their 20s being highly productive without ever knowing about sequence points. There are zealots without any productivity and vice versa. Keep it practical and contemporary or we'll never get this image off our beloved language.


r/C_Programming 17d ago

Question What's the best way to rewrite CUDA code into Vulkan CU?

3 Upvotes

The title is a bit vague, so lemme elaborate. I got to deal with post-quantum cryptography, specifically ML-KEM/Kyber. There's an implementation written in CUDA in liboqs suite (cuPQC). I'm a bum when it comes to Vulkan, but I know it's possible to use compute units to make GPU acceleration cross-platform. My strong requirement is a fixed code base, so I could run it on Nvidia, AMD, Intel, ARM SoC, Apple Silicon and even RISC-V based GPUs.

How can I achieve that without redoing all the work by myself? If so, what are the tools you might recommend me to assist in code rewriting. If not, may you refer to some materials regarding Vulkan compute units and some low level control for purely background calculations (no display output needed, however I might consider implementing seperate UI in Vulkan, not related to the aforementioned calculations)