RSSAmplifier

citizen428.net · Mar 25, 2026

C Preprocessor Fun

0
Sign in to vote or save

citizen428.net

- fun hacks

A lot of my JustForFun™ hacking happens late at night, often when I have trouble falling asleep. In a recent episode, I wanted to see if I could coax the C preprocessor into something JSX-like. Quite surprisingly, the Mastodon post got a lot of attention, so I wanted to preserve it here.

An xkcd-like cartoon with two characters having the following dialog. “I have an idea!” — “Is it bad? — “Extremely.” ­

#The monstrosity

Anyway, here’s what I came up with:

#define _(...) __VA_ARGS__

#define html_(x) "<html>" #x "</html>"
#define html(x) html_(x)

#define tag(name, x) <name>x</name>
#define tag_attr(name, attrs, x) <name attrs>x</name>
#define tag_void(name, attrs) <name attrs>
#define attr(name, value) name = value

#define head(x) tag(head, x)
#define link(attrs) tag_void(link, attrs)

#define body(x) tag(body, x)
#define div(attrs, x) tag_attr(div, attrs, x)
#define h1(attrs, x) tag_attr(h1, attrs, x)
#define hr <hr />
#define p(attrs, x) tag_attr(p, attrs, x)

As you can see, I got bored at one point and didn’t feel like adding any more tags, as they would all have followed the same pattern. We can use it like this:

#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "abuse.h"

// clang-format off
#define WATER_CSS "https://cdn.jsdelivr.net/npm/water.css@2/out/water.css"

#define HTML                                                              \
  head(                                                                   \
    tag(title, C Preprocessor Abuse)                                      \
    link(_(rel="stylesheet" href=WATER_CSS))                              \
  )                                                                       \
  body(                                                                   \
    div(attr(class, "container"),                                         \
      h1(, C Preprocessor Abuse)                                          \
      hr                                                                  \
      p(, This page was generated entirely by the C preprocessor.)        \
      p(, HTML tags are defined as function-like macros that expand to    \
          angle-bracket syntax. The entire page is a single string        \
          literal assembled at compile time via token stringification.)   \
      tag(blockquote, tag(em, The compiler is the template engine.))      \
      hr                                                                  \
    )                                                                     \
  )
// clang-format on

int main(void) {
  char *response = "HTTP/1.1 200 OK\r\n"
                   "Content-Type: text/html\r\n"
                   "\r\n" html(HTML);

  int fd = socket(AF_INET, SOCK_STREAM, 0);
  int opt = 1;
  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

  struct sockaddr_in addr = {
      .sin_family = AF_INET,
      .sin_port = htons(8080),
      .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
  };
  bind(fd, (struct sockaddr *)&addr, sizeof(addr));
  listen(fd, 1);

  puts("Listening on http://localhost:8080");

  while (true) {
    int client = accept(fd, NULL, NULL);
    char buf[1024];
    read(client, buf, sizeof(buf));
    write(client, response, strlen(response));
    close(client);
  }
}

Here’s the accompanying Makefile:

CC ?= clang
CFLAGS = -std=c23 -Wall -Werror

run: clean abuse
	@./abuse

abuse:
	@$(CC) $(CFLAGS) -I. -o abuse abuse.c

clean:
	@rm -f ./abuse

.PHONY: clean run

The rendered page:

A rendered version of the preprocessor-generated HTML with WaterCSS styling

You can find all three files in this gist.

#Summary

This was fun to do and deepened my understanding of the C preprocessor, so it wasn’t entirely pointless. I’m not gonna use this for anything, and you probably shouldn’t either, but I’m not gonna tell you what to do.

Read the original on citizen428.net

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.