物料粒径与目数对照表 2025-07-01 07:19:41
银行卡开换卡费是什么意思 指的是什么费用 2025-08-26 18:18:19
DNF哪个商人有名 2025-08-22 10:54:16
株洲方特梦幻王国好玩项目一览 2025-06-25 19:45:51
哪些明星是属羊的(盘点属羊的明星有哪些) 2025-08-19 02:42:08
怎么修改icloud密码 2025-08-23 02:34:22
日军侵占上海 2025-07-17 11:21:29
台服手游大全 2025-07-25 19:57:00
萤石C6还是乐橙TP1,安防界巨头的家庭摄像头究竟哪家强? 2025-07-29 05:57:31
苹果电脑卸载软件干净又彻底的方法汇总 2025-06-11 04:18:14

10个C语言(C99)编程技巧:提高效率与可读性

在C语言编程中,我们经常会遇到一些可以提高代码效率和可读性的技巧。以下是我在编写C代码时常用的十个模式和技巧,它们涵盖了从基础的代码简化到复杂的宏定义和状态管理。

1. GNU扩展中的三元运算符

在C语言中,传统的三元运算符?:可以被GNU扩展中的?:所替代,这样可以减少表达式的计算次数。例如:

int a = 10;

int b = 20;

int max = a > b ? a : b; // 传统写法

int max = a > b ?: b; // GNU扩展写法

2. 智能向量类型

通过未命名的结构体,我们可以创建灵活的数据结构,如vec3_t:

typedef union {

struct { float x, y, z; };

struct { vec2_t xy; };

struct { float x_; vec2_t yz; };

float v[3];

} vec3_t;

#define VEC3(x, y, z) { {x, y, z} }

...

vec3_t vec = VEC3(1, 2, 3);

// We can access the attributes in different ways.

float x = vec.x;

vec2_t xy = vec.xy;

float z = vec.v[2];

3. IS_DEFINED宏

这个宏用于检查预处理器值是否定义为1,常用于条件编译:

// As used in the linux kernel.

// A macro that expands to 1 if a preprocessor value

// was defined to 1, and 0 if it was not defined or

// defined to an other value.

#define IS_DEFINED(macro) IS_DEFINED_(macro)

#define MACROTEST_1 ,

#define IS_DEFINED_(value) IS_DEFINED__(MACROTEST_##value)

#define IS_DEFINED__(comma) IS_DEFINED___(comma 1, 0)

#define IS_DEFINED___(_, v, ...) v

// Can be used in preprocessor macros:

#if IS_DEFINED(SOMETHING)

...

#endif

// Or even directly in the code.

// Same effect but looks better.

if (IS_DEFINED(SOMETHING)) {

...

}

4. OpenGL代码便利宏

在调试模式下自动检查OpenGL错误,简化错误处理:

// Not really special, but so useful I thought

// I'll put it here. Can also be used with other

// libraries (OpenAL, OpenSLES, ...)

#ifdef DEBUG

# define GL(line) do { \

line; \

assert(glGetError() == GL_NO_ERROR); \

} while(0)

#else

# define GL(line) line

#endif

// Put GL around all your opengl calls:

GL(glClear(GL_COLORS_MASK));

GL(pos_loc = glGetAttribLocation(prog, "pos"));

5. 数组大小宏

通过ARRAY_SIZE宏计算数组大小,提高代码复用性:

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

int array[] = {1, 2, 3, 4, 5};

int size = ARRAY_SIZE(array);

6. 安全最小值宏

使用GNU扩展定义min宏,避免类型不匹配问题:

#define min(a, b) ({ \

typeof(a) _a = (a); \

typeof(b) _b = (b); \

_a < _b ? _a : _b; \

})

7. 传递未命名变量指针

直接将未命名变量作为指针传递给函数,简化代码:

// A func that expects a pointer to three int values.

void func(const int *arg);

// Instead of using a local variable.

int tmp[] = {10, 20, 30};

func(tmp);

// We can write.

func( (const int[]){10, 20, 30} )

// Can be useful with a helper macro.

#define VEC(...) ((const int[]){__VA_ARGS__})

func(VEC(10, 20, 30));

// (Also works with struct or any other type).

8. 命名初始化器

使用宏定义简化结构体的初始化,提供默认值:

// 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}, \__LINE__

__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});

9. X宏

通过宏定义和枚举创建和管理枚举和数组,提高代码的模块化:

// Define this once.

#define SPRITES \

X(PLAYER, "atlas_0.png", {0, 0, 128, 128}) \

X(ENEMY0, "atlas_0.png", {128, 0, 128, 128}) \

X(ENEMY1, "atlas_2.png", {0, 0, 64, 64}) \

...

// Create an enum with all the sprites.

emum {

#define X(n, ...) SPR_##n,

SPRITES

#undef X

}

// Create an array with all the sprites values.

struct {

const char *atlas;

int rect[4];

} sprites[] = {

#define X(n, a, r) [SPR_##n] = {a, r},

SPRITES

#undef X

};

// Many other possibilities...

10. 状态机助手

使用__LINE__宏简化状态机的实现,减少代码冗余:

// This is a great trick.

// Instead of:

int iter(int state) {

switch (state) {

case 0:

printf("step 0\n");

return 1;

case 1:

printf("step 1\n");

return 2;

case 2:

printf("step 2\n");

return 3;

case 3:

return -1;

}

}

// We can define:

#define START switch(state) { case 0:

#define END return -1; }

#define YIELD return __LINE__; case __LINE__:;

// And now the function can be written

int iter(int state) {

START

printf("step 0\n");

YIELD

printf("step 1\n");

YIELD

printf("step 2\n");

END

}

// It is possible to go totally wild with

// this one.

这些技巧可以帮助你编写更高效、更易于维护的C代码。希望这些技巧对你的项目有所帮助!