/r/Cprog

Photograph via snooOG

For C programmers by C programmers. We welcome all interesting content related to the C programming language: projects, papers, blog posts, code, books, debates, whatever!

For C programmers by C programmers.

We welcome all interesting content related to the C programming language: projects, papers, blog posts, code, books, debates, whatever! Here are some sources for C links.

If you have a question about the C language, or if you need help writing your code, please direct your questions to /r/C_Programming, or to Stack Overflow.

Submissions are tagged according to their content, making this subreddit act as a categorized database of links.

The content-type flairs are: text, code, discussion, tinycode, book, library, tool, quiz, slides, talk, picture, and meta.

The topic flairs are: systems, language, algorithms, networks, osdev, science, webdev, virtualization, compilers, security, funcprog, embedded, assembly, performance, parallelization, correctness, graphics, gamedev, databases, ai, tooling, building, testing, debugging, oop, career, news, learning, history, and humor.

You can combine these flair operators by: flair:code flair:systems, and filter certain flairs by: flair:text -flair:code.

/r/Cprog

4,292 Subscribers

3

suggest some c language blogs....

3 Comments
2022/11/20
16:39 UTC

11

Any C books like "Black Hat Python" or "Black Hat Go", focusing on infosec aspects, but purely in C ?

1 Comment
2022/10/22
11:45 UTC

11

GNU Makefile Tutorial (without headache) 🍃

I wrote this tutorial because the others that I found were overloaded or contradicting each other, so I went in search for the best practices to gather them in practical examples and I reduced the scope of the tutorial on the most general applications. I hope you will finally enjoy Makefiles

➡️ https://github.com/clemedon/Makefile_tutor

For the moment 5 Makefiles are studied:

    v1-3   Build a C project
    v4     Build a C static library
    v5     Build a C project that uses libraries
1 Comment
2022/10/06
15:00 UTC

2

How are static and global variables initialized?

0 Comments
2022/10/05
00:26 UTC

10

Extensible overloading and ad-hoc polymorphism

So _Generic is pretty cool, but it has a major limitation (among others :P) - the set of overloaded functions has to be fixed at the time you declare the overloaded name:

#define cbrt(X) (_Generic((X) \
  , float : cbrtf         \
  , long double : cbrtl  \
  , default : cbrt) (X))

If you wanted to add, say, cbrti, you're out of luck. You can't just define a new cbrt in terms of the old one because macros don't work that way; and indeed, it even already relies on that behaviour having exactly one level that doesn't do macro lookup for the existing default association.

Which is a nuisance because sometimes we want to define algorithms in terms of the component operations but leave the set of supported types open to whatever the user includes, from builtins, library types, and even new user-defined types we haven't seen before. The classic example of this is of course the STL, that evolved into the C++ standard container and algorithm libraries. And although there are some truly heroic approaches to defining generic containers in C, I haven't personally encountered one that can offer things like generic traversal across an arbitrary container the way std::for_each might - because with fixed overload sets you need to know the type of every supported container up-front.

Well, maybe this isn't quite true...

It turns out, there is actually a way to extend macros in-place! Actually there are probably better ways - almost certainly, if this is the one I could work out - but this is a simple starting point and can probably be refined into one of those up/down continuation-drivers later.

Given a suitably large finite list of numbered macro expansions where each definition refers to the previous numbered macro in the sequence, we can rewrite a single overload macro as a list of overload macros that each handle a single type and then default on to the next one:

#define cbrt_0(X) cbrt
#define cbrt_1(X) _Generic((X), long double : cbrtl, default : cbrt_0 (X))
#define cbrt_2(X) _Generic((X), float : cbrtf, default : cbrt_1 (X))

#define CBRT_START 2
#define cbrt(X) GLUE(cbrt_, CBRT_START) (X) (X)

Now if we want to add a cbrti, we can just slot it in at cbrt_3 and increment the value of CBRT_START to reflect the new starting point in the chain.

Actually, that's it! That's the basic principle. However, there are some complexities.

Firstly, you won't generally know the value of the starting point - in this case it's trivial, unconditional #undef followed by #define CBRT_START 3. However, the whole point of extensible overloading is that it should be independent of the amount of code already loaded - we shouldn't need to know which datatypes have been included or their order, or we're essentially just operating in a distributed version of the original problem where you need to know about all overloads that will make it into your program, at the time when you define one overload.

Luckily, using a trick that I stole from Boost.Slots (no idea who the original inventor is), we actually can define an incrementable counter that doesn't rely on needing to know the previous value: type_counter.h. Used as follows:

#define INCR_COUNTER "type_counter.h"

#include INCR_COUNTER
_Static_assert (TYPE_COUNTER == 0, "");
#include INCR_COUNTER
_Static_assert (TYPE_COUNTER == 1, "");
#include INCR_COUNTER
_Static_assert (TYPE_COUNTER == 2, "");

// can even be manually adjusted or reset
#define TYPE_COUNTER 13

#include INCR_COUNTER
_Static_assert (TYPE_COUNTER == 14, "");
#include INCR_COUNTER
_Static_assert (TYPE_COUNTER == 15, "");

Now the Boost technique just expands the value to an expression, but with a bit of work we can make the counter expand to a valid single token. In the file above there are expansions for hex literal (0x123abul), binary literal (0b01010 - C23 and GNU), and "plain" hex (123ab) - the last one is most useful for gluing to form names.

Combining this incrementable counter with the linked-generic-list structure shown above is actually enough to implement extensible overloads! Here's a TYPEID macro that returns a unique integer for every registered distinct type, regardless of representation: typeid.h

As you can see, the implementation does two things: 1) provide a predefined linked list of macros that simply check for a numbered typedefor default to the tail of the list; and 2) in ADD_TYPEID, register the type you want by assigning it to the current "top" typedef number, and increment the start point to check that now-valid typedefname.

The trick here is that we can't programmatically create macro bodies or names, but we can create a generic macro body framework that requires C names - which we can generate programmatically - in order to work.

Demonstrated:

#include "typeid.h"

_Static_assert (TYPEID (void) == 0, "");

_Static_assert (TYPEID (int) == 6, "");
// _Static_assert (TYPEID (int) == 13, ""); // fails

_Static_assert (TYPEID (double) == 13, "");
// _Static_assert (TYPEID (double) == 7, ""); // fails

struct Foo { int x; };
struct Bar { int x; };

#include TYPEID_COUNTER
ADD_TYPEID (struct Foo)
#include TYPEID_COUNTER
ADD_TYPEID (struct Bar)

_Static_assert (TYPEID (struct Foo) == 15, "");
_Static_assert (TYPEID (struct Bar) == 16, "");

TYPEID is an extensible overloaded function, behaving semantically as though you were adding more overloads in C++! All do-able in C11 as well (although C23 typeof makes it a little neater as it can also admit function/array types and their pointers).


So how about those generic algorithms that were the real motivating case, hmm?

Well, we can steal a neat concept from Haskell implementations called "dictionary passing". Without any overloading or macro magic at all, the underlying concept looks like this: explicit-dict.c

Given a ...not exactly interesting generic algorithm that just calls + on its operands:

void useAdd (struct SumInst const sumInst, void * out, void const * lhs, void const * rhs)
{
  sumInst.add (out, lhs, rhs);
}

...we call it with a dictionary object containing the appropriate generic operations for its untyped arguments:

int ri;
float rf;
useAdd (intInst, &ri, ToLvalue (x), ToLvalue (x));
useAdd (fltInst, &rf, ToLvalue (y), ToLvalue (y));

intInst and floatInst are function packs containing the appropriate implementations of + and - for int and float respectively. (ToLvalue is just a neat trick that ensures that even an rvalue like x + 1 can still be passed as an argument that will be converted to void const * - it's not strictly necessary for this.)

...this lets us write a generic adder algorithm, but it's not exactly type-agnostic at the point of use. However, using the same principle that let us define an extensible overload for TYPEID, we can also define an extensible overload for Instance() that will retrieve the appropriate typeclass dict for the concrete argument type, without us needing to know its name: selected-dict.c

Sum intInst = Instance (Sum, int);
Sum fltInst = Instance (Sum, float);

useAdd (intInst, &ri, ToLvalue (x), ToLvalue (x));
useAdd (fltInst, &rf, ToLvalue (y), ToLvalue (y));

These can obviously be inline and don't need declaration - which means, useAdd itself can be wrapped in a macro to select the appropriate typeclass for the argument instance - finally making it syntactically generic: [implicit-dict.c]

#define gAdd1(Ret, L, R)                      \
    useAdd (Instance (Sum, typeof(Ret))       \
          , &(Ret), ToLvalue (L), ToLvalue (R))

gAdd1 (ri, x, x); // no more explicit annotation of the arg type
gAdd1 (rf, y, y); // selects dict automatically

...or if we allow a bit of GNU C to pretty things up:

#define gAdd2(L, R) ({                            \
    typeof (L) _ret;                              \
    useAdd (Instance (Sum, typeof(_ret))          \
          , &(_ret), ToLvalue (L), ToLvalue (R)); \
    _ret;                                         \
  })

ri = gAdd2 (x, x);
rf = gAdd2 (y, y);

Finally, a generic algorithm - even if the example algorithm is pretty dumb - that implicitly selects the appropriate implementation operators for the argument type!

And to prove it, in one final file, we can add a new type that we haven't seen before and watch it "just work" with gAdd: more-types.c

typedef struct Fixie {
  int rep;
} Fixie;

void addFix (void * out, void const * lhs, void const * rhs) {
  ((Fixie *)out)->rep = ((Fixie const *)lhs)->rep + ((Fixie const *)rhs)->rep;
}
void subFix (void * out, void const * lhs, void const * rhs) {
  ((Fixie *)out)->rep = ((Fixie const *)lhs)->rep - ((Fixie const *)rhs)->rep;
}

#include "type_counter.h"
ADD_TYPEID (Fixie);
#include "oper_counter.h"
DefInstance (Sum, Fixie, {
  addFix, subFix
});

...
Fixie rF = gAdd2 (z, z); // yes this actually works with the same gAdd[12] definitions!

The underlying technique for Instance()is a little more complicated than the one for TYPEID, because it takes two arguments - a typeclass, and an instance type to operate on. So we use a slightly more complicated technique that dispatches on both operands at once by combining them into a two-dimensional array type: the two-dimensional array type whose predefined indexed enum dimension values match the TYPEID of the typeclass and the instance, will be selected (this is a generalizable technique for condensing two-dimensional _Generics into a flat list).

A separate counter is needed for the operators because we're counting operations and types separately (unfortunately), but a single OPER big-table with suitably-dimensioned arrays can actually be used for all extensible overloads, not just Instance - this table can return any function (branches do not need to return compatible types) and can share its counter with other overloaded functions if desired.

The best part of all this is that unlike in C++, where useAdd would be a template and thus have no value identity (or, create a new identity on each instantiation), in the typeclass model, it still has a single concrete identity - you can take its pointer and indeed pass it around by value. (You could actually create generic wrappers that call to a function pointer in scope, for instance, and then replace useAdd with useSub and the same generic calls would work transparently!)

So: polymorphic functions, with identity, with quiet ad-hoc support.

:D


If you read to the end, well done, and you're now screaming at the screen that "none of this is type safe AAAAARGH". Well, you're right. But that's a different problem that shares its solution with all parametrically polymorphic functions and is separate from overloading. I propose a totally-unusable C11 solution here: Towards type-checked polymorphism, which eventually evolved into n2853 The void-which-binds. This is being extended into a more complete solution that will also cover structure members, but as it is, it would provide enough type-checking to ensure the examples above can't be misused. (See y'all in C26!)

6 Comments
2022/09/28
15:46 UTC

4

How does the wait() function for semaphores ensure that there is no interruption between evaluating the semaphore and decrementing it?

2 Comments
2022/09/11
19:36 UTC

8

Makefile tutor

Just wanted share a simple Makefile tutorial I have just written past few days with the intention of seeing more clearly without having a headache through the progressive and documented evolution of a template. 🌱🧠✅

https://github.com/clemedon/Makefile_tutor

This is just the beginning but I am at the step where I need feedbacks. 📝

And above all I would be very happy if it could help beginners who would pass by here to see more clearly in their Makefiles. ✨

2 Comments
2022/09/01
18:54 UTC

2

Build KDE software using VS Code

0 Comments
2022/08/26
11:30 UTC

2

When is it appropriate to use GOTO?

8 Comments
2022/08/07
18:49 UTC

9

What are some good resources/books to learn specifically about how to use the new features in C99, C11, and C23?

1 Comment
2022/08/06
17:18 UTC

1

socket

I'm trying to make a tcp socket, I managed to do it with internet etc locally with the server and client on the same machine but now I have to do it on 2 different machines one that will be the server and the other the client but I'm having a bit more trouble. I'm not sure how to do this, but I'm not sure if it's a good idea to use the server or the client, but I'm not sure if it's a good idea to use the server or the client. It tells me error binding

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

int main(){

int server_sock, client_sock;

int server_port = 4444;

char *server_ip = "192.16.1.16";

char buffer[1024];

char *client_ip = "192.16.1.40";

//Création du socket

server_sock = socket(AF_INET, SOCK_STREAM, 0);

if(server_sock<0) {

printf("erreur");

exit(1);

}

printf("c est creer.\n");

struct sockaddr_in server_addr;

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(server_port);

server_addr.sin_addr.s_addr = inet_addr(server_ip);

struct sockaddr_in client_addr;

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(server_port);

server_addr.sin_addr.s_addr = inet_addr(client_ip);

int bind_result = bind(server_sock ,(struct sockaddr *)&server_addr,sizeof(server_addr));

if (bind_result<0)

{

printf("error binding.\n");

exit(1);

}

else

{

printf("listening on %s:%d\n" ,server_ip,server_port);

}

listen(server_sock, 5);

printf("listening\n");

int len = sizeof(client_addr);

client_sock= accept(server_sock,(struct sockaddr *)&client_addr,&len);

printf("client connected .\n");

0 Comments
2022/07/27
14:52 UTC

1

Why is 0 (null) considered to be a safe pointer?

1 Comment
2022/06/18
18:12 UTC

4

Need help

Im a first year computer engineering student and i have a prog project to prepare today. It’s almost done but still struggling with some parts. Is there anyone available to help?

1 Comment
2022/04/26
18:30 UTC

3

In C/C++, how can you tell if the sizeof operator will give you the size of the whole array or that of a pointer?

1 Comment
2022/04/09
17:02 UTC

1

How do i resolve this error? I am trying to do a selection sort of my Struct array but I get this error and i don't understand why. Can someone help me?

5 Comments
2022/04/06
09:28 UTC

5

Historical Roots of C - The Unix Operating System

0 Comments
2022/01/11
21:55 UTC

13

Good C Source Code

Hi guys. I'm putting together a curated index of high quality source code at goodsourcecode.org. The goal is to create a really nice collection of exemplary source code, searchable by language and concept tags, that developers can use to understand how different ideas are implemented in practice, and how those implementations interact with other components.

If anyone has any examples of good C source code, please share!

The more detail the better. What makes the suggested source code good? This will inform what tags are used for indexing.

3 Comments
2022/01/06
14:37 UTC

3

Copying the content of one binary file to another in c

C we copy the content of one binary file to another, without using the buffer or dynamic memory allocation.

I tried copying the file to another file by using fgetc and fputc but it's not working. Is there any other way?

4 Comments
2021/09/14
18:27 UTC

4

C Programming for Beginners Full Course in 6 hours free on YouTube

0 Comments
2021/08/04
02:46 UTC

1

is anyone using c with swift ui kit in xcode

hello im look for somone who is using swift ui and c programmming so i can see they github and copy some of the examples so i can learn how to use c and swift ui i have found a few things online . but i like to have complete examples so i can learn how it works .

14 Comments
2021/07/24
18:41 UTC

2

Made utility for adding constant velocity to mouse through cli for tiling window managers.

0 Comments
2021/07/10
16:56 UTC

9

Defined or UB? ;D

Consider this snippet at block scope:

int x = 1;
int *p = &x;
a:
  if (*p && (p = &(int){ 0 }))
    goto a;

Is this UB, or is it well-defined?

Hint 1: this is UB in the current draft of C23 due to accidental implications of a change to the label rules

Hint 2: when this example was shown to WG14 at last week's meeting, the group went silent and we all agreed to go away and think about it in shame for a bit, because... hell if a room full of implementors know!

What would you expect here?

3 Comments
2021/06/19
16:45 UTC

7

Any C work at kernel/user space boundary?

0 Comments
2021/05/14
17:53 UTC

Back To Top