Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Preprocessors and Macros

Name: Anonymous 2014-01-25 0:17

I have never encountered anything more pointless and stupid in my years of programming, EVER.

It's pretty much the only thing that holds me back from giving contributions to most open source C programs. Every source file is littered with #ifndefs every-fucking-where. 90% of the code is preprocessor directives and the rest is real C code. It's so fucking pointless and it's not even metaprogramming. I mean #define for using constants? Really? Can't you just use const for that? Sure, it's useful for separating your header files and relating functions in their source files but that's it. Dennis Ritchie should have just built that in the language. Sure, it's also useful compiling different lines of code for different kernel versions or different CFLAGS but whatever, it just proves how broken a programming language is.

What do you think /prog/? I've only parroting C shit, how does your favorite use macros?

Name: Anonymous 2014-01-25 22:52

#define is pretty ugly, I wish C had real module and macro systems. That said, it's an extremely useful tool and your code is probably worse than it should be if you aren't making use of it.

I mean #define for using constants? Really? Can't you just use const for that?

I can't remember off the top of my head, but there actually are plenty of situations in C where it refuses to treat a const variable as an actual constant, because someone retard and used pointer arithmetic to modify a const variable. I don't remember if int nums[some_const_variable]; works, but I do know that _Static_assert(some_const_variable == 5); fails. You could also use an enum, but #define is the easiest and most flexible way to define constants.

#ifdefs is the most straightforward way to do cross-platform code in C. You can have a separate windows.c and unix.c file for the big differences, but for the little ones, this is so much easier:

#ifdef WINDOWS
// stupid bullshit
#else
// what every other operating system expects
#endif


X-macros are great for working with lots of constants, as well as parallel arrays. The idea there is you have a big file full of a macro invocations for an undefined macro, and then you define the macro in another just before you include the file full of data. Example:

// monster.i
MONSTER("bat", 5, 2);
MONSTER("mummy", 20, 10);
MONSTER("zombie", 15, 7);
MONSTER("dragon", 100, 30);

// monster.h
typedef struct monster_t {
const char *name;
int health, strength;
} monster_t;
#define MONSTER(name, health, strength) extern monster_t monster##name
#include "monster.i"
#undef MONSTER

// monster.c
#include "monster.h"
#define MONSTER(name, health, strength) monster_t monster_##name = { name, health, strength }
#include "monster.i"
#undef MONSTER


I didn't compile that, so there's probably some syntax errors and other fuckups, but you get the idea. You could maintain those definitions separately, but it's just more pointless work than necessary.

That was pretty easy to understand, but at some point, macros become black magic. See klib1, which implements efficient type-generic data structures in plain C. They're way more efficient than a vanilla C implementation, because they don't box the elements and they can specialize on the type (ie, the compiler can know that the data field for a hash table of struct foos is 16 bytes, instead of having to have that value passed in as a parameter to a function that operates on elements of any size). At the same time, I have a really hard time reading the source, which scares me.

tl;dr macros are useful. In an ideal world, we'd be doing our low level work in ``cisp,'' but this is the real world, so you have to put up with this shit if you don't want to go insane writing C.

[1] https://github.com/attractivechaos/klib

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List