💾 Archived View for soviet.circumlunar.space › ayb › lab › modules.gmi captured on 2023-05-24 at 18:35:08. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

Namespaces in C

One of the critisiscm often made to C is that it doesn't support namespaces and modules, forcing programmers to use weird prefixes before the name of their functions and variables. But what if I told you that, the following code is valid C:

#include <io.h>

int
main()
{
	io.println("Hello, world!");
}

C programmers are probably asking themselves what the hell is that heresy. The answer is simple, two simple C concepts structs and function pointer, here is the content of io.h - without include guards -:

struct io_module {
	void (*println)(char *);
};
extern struct io_module io;

We can see that io is, in fact, a struct containing a pointer to the actual function, allowing to access it the usual dot operators.

The implementation is in io.c:

#include <stdio.h>

#include "io.h"

void println(char *s);

struct io_module io = {
	println
};

void
println(char *s)
{
	puts(s);
}

Using that method you can also have submodules, global variables avoid the problems caused by the single namespace of C. Suppose that io has a submodule fmt, you can even have module aliases like:

struct module_fmt = io.fmt;

A problem of this technic is that you have define the type of your function twice, once in the module declarartion and one in the actual declaration of the function, but the header could easily generated by a small script. The main problem, is performance, it main not be issue in small programs but, if the compiler doesn't know that the function won't change, it won't be able to just use the name in the function in the generated code. It will have to access memory once to get the address on the function before being able to call it.

source code