( Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu )1、C 类型定义using / typedef / #define / constexpr 对比using、typedef、#define、constexpr是 C 给类型或值起别名的核心关键字。using/constexprC11 现代写法强烈推荐typedef老式写法仅兼容旧代码#define纯文本替换严禁用于类型/常量下面从用途、原理、作用域、安全性方面列表对比来看。列表对比关键字本质用途作用域类型安全推荐度usingC11 现代别名类型别名首选编译期、作用域安全✅ 强类型安全⭐⭐⭐⭐⭐typedefC 老式别名类型别名兼容旧代码编译期、作用域安全✅ 强类型安全⭐⭐⭐#define纯文本宏替换文本替换极不推荐用于类型全局、无作用域❌ 无类型、易出BUG⭐constexpr编译期常量表达式常量值定义编译期、作用域安全✅ 强类型安全⭐⭐⭐⭐⭐归纳总结定义类型别名 → 优先用using函数指针也用它定义编译期常量 → 用constexpr替代define方式的常量定义绝对不要用#define定义类型/常量typedef 仅用于兼容旧代码。定义类型别名定义编译期常量禁止操作兼容场景开始需要定义类型/常量需求类型优先使用 using使用 constexpr绝对不要用 #define 定义类型typedef 仅用于兼容旧代码结束2、代码样例类型别名 → 用 using推荐编译期常量 → 用 constexpr❌ 禁止#define 定义类型typedef仅兼容旧代码#includearray#includevector#includemap#includestring// // 1. 类型别名 → 用 using推荐// using MyIntint;using StrMapstd::mapstd::string,std::string;// 函数指针最清晰写法using FuncPtrvoid(*)(int,double);// 模板别名using 独有功能templatetypename Tusing MyVecstd::vectorT;// // 2. 编译期常量 → 用 constexpr// constexprintMAX_COUNT100;constexprdoublePI3.14159;constexpr bool IS_DEBUGtrue;// 用于数组大小 / 模板参数constexprintARR_SIZE5;intarr[ARR_SIZE];// 数组大小std::arrayint,ARR_SIZEarr_std;// 模板参数// // 3. ❌ 禁止#define 定义类型// // #define MyInt int* // 纯文本替换极易出 Bug// // 4. typedef仅兼容旧代码// typedefintOldInt;typedefvoid(*OldFuncPtr)(int);3、语法详解3.1.usingC11 现代类型别名最推荐、最强大、语法最直观完全替代typedef。语法新名字 旧类型直观易懂支持函数指针、模板别名typedef 做不到作用域安全在类/函数内定义只在内部生效编译期处理无运行时开销用法// 给类型起别名usingMyIntint;usingStrVectorstd::vectorstd::string;// 函数指针别名比 typedef 好读 10 倍usingFuncPtrint(*)(int,int);// 模板别名typedef 做不到templatetypenameTusingVecstd::vectorT;3.2.constexpr编译期常量表达式不是类型别名是定义编译期常量常用来替代define方式的常量定义例如定义PI值均应优先使用constexpr方式。用途数组大小、模板参数、全局常量配置特点类型安全作用域安全编译期求值无运行时开销用于常量值不是给类型起别名用法constexprintMAX1024;constexprintsquare(intx){returnx*x;}constexprintressquare(10);// 编译期直接算出 1003.3. typedef老式类型别名C 语言遗留C 为了兼容保留语法不易懂不推荐新代码使用。语法顺序混乱typedef 旧类型 新名字不支持模板别名复杂类型可读性极差如函数指针、嵌套类型// 等价于 using MyInt int;typedefintMyInt;// 函数指针可读性差等价于using FuncPtr int(*)(int, int);typedefint(*FuncPtr)(int,int);3.4. define定义纯文本宏危险预处理阶段文本替换不是类型定义绝对不要用来定义类型。预处理阶段替换不是 C 语法无作用域、无类型检查、极易产生隐蔽 Bug#defineMyIntint*MyInt a,b;// 展开后int* a, b;// a 是指针b 是普通 int完全错误4、关键的区别~面试常问4.1.usingvstypedef都是类型别名using语法更清晰支持模板是现代 C 标准typedef语法不易懂无模板支持仅用于兼容旧代码规则新项目一律用using不用typedef。4.2. 宏#define真的危险吗因为define是纯文本替换不是类型定义会产生难以发现的 Bug。非常危险看这个经典BUG#defineMyIntint*MyInt a,b;// a 是指针b 是 intusingMyIntint*;MyInt a,b;// a、b 都是指针正确4.3.constexpr到底干嘛的它不定义类型别名只定义编译期就能确定的值用于数组大小模板参数常量配置示例// 1. 数组大小constexprintN10;intarr[N];// 合法N 是编译期常量// 2. 模板参数constexprintARRAY_SIZE5;std::arrayint,ARRAY_SIZEmy_array;// 3. 常量配置constexprdoublePI3.1415926;// 不建议的方式#defineN10intarr[N];// 也能用但不安全、无类型5、总结实践5.1 推荐用法#includevector#includemap#includearray#includestring// 类型别名usingUserIdint;usingUserMapstd::mapstd::string,UserId;usingLogicFuncbool(*)(int);// 模板别名templatetypenameTusingMyArraystd::vectorT;// 编译期常量constexprintMAX_USER1024;constexprdoubleCIRCLE_RATE3.1415926;constexprintBUF_SIZE64;// 编译期常量用于容器模板参数std::arrayint,BUF_SIZEbuf;5.2 总结给类型起别名优先using完全替代typedef定义编译期常量用constexprtypedef仅维护旧代码时使用新项目不用文本宏define绝不用于类型/常量只在极端底层场景使用( Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu )