面试题答案
一键面试重构思路和方法
- 使用常量和枚举替换简单宏:对于简单的数值替换,如
#define PI 3.1415926
,可以使用const double PI = 3.1415926;
替代。对于表示状态或选项的宏,使用枚举,例如#define STATUS_OK 0 #define STATUS_ERROR 1
,可改写为enum Status { STATUS_OK = 0, STATUS_ERROR = 1 };
。这样做不仅提高了类型安全性,而且编译器在优化时更容易处理。 - 内联函数替代宏函数:对于有简单逻辑的宏,如
#define SQUARE(x) ((x) * (x))
,使用内联函数inline int square(int x) { return x * x; }
替代。内联函数在编译时进行优化,且有更好的类型检查,避免了宏可能带来的副作用,如SQUARE(a++)
宏展开可能出现的问题。 - 条件编译优化:如果
#define
用于条件编译,如#define DEBUG 1
,可以使用命令行参数或配置文件来控制编译选项。在Makefile中可以设置CFLAGS=-DDEBUG
来开启调试模式,代码中通过#ifdef DEBUG
等条件编译语句来处理不同模式下的代码。这样可以使代码在不同构建环境下更灵活,并且在不需要调试时不会将调试代码编译进去,提高编译速度。
处理复杂宏定义(带有可变参数的宏)
例如,有一个日志记录的可变参数宏#define LOG(...) printf(__VA_ARGS__)
。重构时可以使用_Generic
特性(C11及以上),结合内联函数来实现更安全和可维护的代码。
#include <stdio.h>
// 定义日志函数
void log_message(const char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
// 使用内联函数包装
inline void log_wrapper(const char *format, ...) {
va_list args;
va_start(args, format);
// 这里可以添加额外的日志处理逻辑,如时间戳等
vprintf(format, args);
va_end(args);
}
在使用时,直接调用log_wrapper
函数,如log_wrapper("This is a log message: %d\n", 42);
,相比宏,函数调用更安全,并且在优化时编译器可以更好地处理。同时,如果有更复杂的日志需求,在函数内部添加逻辑也比在宏中更容易维护。