c 语言技巧

2023年03月23日 09:23GMT+8

一些 c 语言技巧

可以使用 #define 代替 struct 来定义公共字段, 因为一些编译器可能不支持匿名结构(unamed struct), 还有 struct 可能因为要对齐, 浪费了字节.

/* Common GC header for all collectable objects. */
#define GCHeader    GCRef nextgc; uint8_t marked; uint8_t gct

CLAMP

通过添加临时变量, 消除条件检测 data 时的副作用, 使得编译器能编译成 “无分支” 的语句.

// 在 msvc, gcc 中都能被优化
#define CLAMP(data, min, max) do {   \
	int tmp = data;              \
	if (tmp < (min)) data = min; \
	if (tmp > (max)) data = max; \
} while (0)

// 在 gcc 中能被优化, 但 msvc 不能
#define CLAMP(data, min, max) data = (data) < (min) ? (min) : ((data) > (max) ? (max) : (data))

unsigned

在使用无符号数时, 要特别小心减号”-“ 的使用, 对于 “+” 要考虑到溢出的情形(虽然很少有溢出的状况).

Named initializer, with default values

// I use this one all the time when writing
// video game.  One of the reason why I
// don't like to use C++.

// Let say we have this struct
struct obj {
    const char *name;
    float pos[2];
    float color[4];
};

// We can write a macro like this one
#define OBJ(_name, ...)             \
    (struct obj) {                  \
        .name = _name,              \
        .color = {1, 1, 1, 1},      \
        __VA_ARGS__                 \
    };

// Now we can use the macro to create new objects.
// This one with color defaulted to {1, 1, 1, 1}.
struct obj o1 = OBJ("o1", .pos = {0, 10});
// This one with pos defaulted to {0, 0}.
struct obj o2 = OBJ("o2", .color = {1, 0, 0, 1});