C 语言作为一门接近硬件的编程语言,以其灵活性和强大的底层控制能力著称。在长期的实践中,开发者们总结了许多“奇技淫巧”(高级技巧或非传统用法),这些技巧可以帮助我们写出更高效的代码,但也可能牺牲可读性和可移植性。本文将介绍一些常见的 C 语言技巧,并附上代码示例,供大家参考和学习。
1. 预处理宏的魔法
1.1 代码生成
通过宏可以生成重复的代码,减少手动编写的工作量
#define DEFINE_FUNC(type) \
type add_##type(type a, type b) { return a + b; }
DEFINE_FUNC(int) // 生成 int add_int(int a, int b) { ... }
DEFINE_FUNC(float) // 生成 float add_float(float a, float b) { ... }
1.2 编译时断言
利用宏在编译时进行断言检查
#define STATIC_ASSERT(cond) typedef char static_assert[(cond) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4); // 如果 int 不是 4 字节,编译失败
2. 位操作黑科技
2.1 快速乘除
通过位操作实现快速的乘除法
int a = b << 3; // 等价于 b * 8
int c = d >> 2; // 等价于 d / 4(仅适用于正数)
2.2 交换变量
使用异或操作交换两个变量的值,无需临时变量
a ^= b; b ^= a; a ^= b; // 异或交换(但可读性差,且对浮点数无效)
2.3 判断奇偶性
通过位操作快速判断一个数的奇偶性
if (n & 1) { /* 奇数 */ }
3. 指针的骚操作
3.1 偏移指针访问结构体
通过指针偏移访问结构体成员
struct Data { int x; double y; };
struct Data d;
double *py = &d.x + 1; // 假设内存对齐允许(可能未定义行为!)
3.2 通过空指针访问成员
计算结构体成员的偏移量
#define offsetof(type, member) ((size_t)&((type *)0)->member)
// 计算结构体成员的偏移量(标准库已实现,但原理如此)
4. 结构体内存布局控制
4.1 位域节省内存
使用位域来节省内存空间
struct Buffer {
size_t length;
char data[]; // C99 柔性数组,用于动态分配内存
};
struct Buffer *buf = malloc(sizeof(struct Buffer) + 100);
5. 利用未定义行为(慎用!)
5.1 类型双关(Type Punning)
直接读取浮点数的二进制表示
float f = 1.0;
int i = *(int *)&f; // 直接读取 float 的二进制表示(需注意字节序)
5.2 通过指针修改常量
通过指针修改常量的值(不可靠)
const int x = 42;
int *p = (int *)&x;
*p = 100; // 未定义行为!某些平台会崩溃
6. 内联汇编优化
在关键代码中嵌入汇编以提升性能(平台相关)
int add(int a, int b) {
__asm__("addl %%ebx, %%eax;" : "=a"(a) : "a"(a), "b"(b));
return a;
}
7. 函数指针的妙用
7.1 动态分发
通过函数指针实现动态分发
void (*func_ptr)(int) = NULL;
func_ptr = &my_function;
func_ptr(42); // 调用函数
7.2 模拟面向对象
使用函数指针模拟面向对象编程
typedef struct {
void (*print)(void *self);
} Object;
void String_print(void *self) { printf("%s\n", (char *)self); }
Object str_obj = { .print = String_print };
str_obj.print("Hello");
8. 代码优化技巧
8.1 循环展开
通过循环展开减少循环开销
for (int i = 0; i < 100; i += 4) {
process(i); process(i+1); process(i+2); process(i+3);
}
8.2 查表法代替计算
使用查表法代替复杂的计算
static const int sin_table[360] = {0, ...};
int sin_value = sin_table[angle % 360];
9. 利用编译器扩展
9.1 分支预测提示(GCC)
通过编译器扩展提示分支预测
if (__builtin_expect(condition, 0)) { // 提示编译器 condition 可能为假
// 处理冷门分支
}
9.2 编译时计算(C11 constexpr)
在编译时进行计算
constexpr int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n-1); }
10. 非常规代码生成
10.1 自修改代码
生成自修改代码(需关闭内存保护)
void (*func)() = (void (*)()) malloc(100);
// 向 func 指向的内存写入机器码(高度平台相关,现代系统通常禁止)
注意事项
-
可读性 vs 性能:多数技巧会降低代码可读性,仅在必要时使用(如嵌入式系统或性能关键代码)。
-
未定义行为:部分技巧依赖编译器或平台(如内存对齐、字节序),需谨慎验证。
-
现代替代方案:C11/C17 标准已引入更安全的特性(如
static_assert),优先使用标准方法。
结语
C 语言的这些“奇技淫巧”展示了其强大的底层控制能力,但在实际项目中应权衡利弊,优先保证代码的健壮性和可维护性
📦 硬核资料赠送
>>搓这里关键字>>「C++王者」获取:
1. 《C++后端开发高频八股文》(涵盖23个核心考点)
2. 《C/C++工程师能力自测清单》(50+项技能树Checklist)
3. 【开源项目】libevent-master
4. 【开源项目】workflow-master
5. 《LeetCode 101算法精讲》(剑指Offer最优解合集)

1万+

被折叠的 条评论
为什么被折叠?



