Appearance
define / const / inline / typedef / casting 杂项辨析
一、define vs const
| 维度 | #define(宏) | const |
|---|---|---|
| 处理阶段 | 预处理(文本替换,无类型检查) | 编译期(有类型系统) |
| 类型/作用域 | 无语义,无作用域,全局文本 | 类型安全、遵循作用域/链接规则 |
| 内存 | 只是替换;不占数据段(预处理后消失) | const 对象存数据段/栈 |
| 调试 | 断点/反混淆难 | 常规变量可查 |
const int vs #define N | 可能被误用为常量折叠差异在表达式求值 | 可入 switch/模板定长等需常量表达式处(或用 constexpr) |
结论:常量优先用 const/constexpr 而非 #define,只有真正的「文本替换/代码宏」才用 define。
二、define vs inline
#define 宏函数 | inline | |
|---|---|---|
| 类型检查 | 无(文本替换) | 有,编译器严格类型检查 |
| 求值次数 | 参数表达式可能被多次求值(如 MAX(a++,b) 副作用大) | 作为函数不求值多次 |
| 调试 | 无 | 有符号可调试 |
| 是否真内联 | 纯文本替换 | 编译器决定(建议性,可能不内联) |
| 规则 | 需小心括号 | 正常函数语义 |
教训:现代 C++ 用 constexpr/inline/模板替代宏函数避免副作用与类型 bug。
三、typedef vs using(类型别名)/ 与 define 差别
typedef int MyInt;定义类型别名。- C++11
using MyInt = int;更清晰、可模板化(template<...> using)。 - define 是纯文本替换:不能定义一个真正的类型(无作用域、无检查),如
#define INT int只是替换为 int,且会全局污染。
四、四种 cast(必考)
| cast | 用途 | 风险 |
|---|---|---|
static_cast<T>(expr) | 编译期:数值类型转换、基类→派生(下行)的多态安全转换依赖静态检查与运行期验证缺省 | 下行不含运行期检查(前提保证正确否则 UB) |
dynamic_cast<T*>(expr) / & | 含多态(需 vtable)的运行期类型转换 | 失败返回 nullptr(指针)/ 抛 bad_cast(引用) |
const_cast<T>(expr) | 去掉/加上 const/volatile | 去掉后写原 const 对象=UB |
reinterpret_cast<T>(expr) | 位级重解释(指针↔整数等) | 几乎不检查,最危险 |
什么时候用哪个
- 常规安全转换:
static_cast。 - 运行时确定是否派生类实例:
dynamic_cast(要求基类有虚函数)。 - 只想去 const:
const_cast(如调一个改了但接口本想只读的第三方函数,需谨慎)。 - 无相关类型强转/底层位视图:
reinterpret_cast(几乎只在硬件/序列化)。
问题
- C 风格
(T)x= 尽可能的组合 cast,不推荐(能偷偷做 reinterpret/const,缺检查)。 dynamic_cast为什么需要 vtable?—— 靠 runtime type 信息 RTTI 查实际类型,vptr 尾部有 type_info(见 oop/vtable)。
五、sizeof / strlen / 数组名
sizeof:编译期计算类型/表达式所占 字节(sizeof(array)=整块)。strlen:运行期数到 '\0' 的长度(不含结尾 0)。- 数组传给函数形参退化为指针 →
sizeof(arr)变 8(指针),经典坑。 sizeof(1==1):C 中int=4;C++ 中 bool 通常 1 字节 → 结果实现相关(多数 =1),因比较产生 bool。这也是小林那篇的题:C 里 1==1 是 int 4,C++ 里是 bool 通常 1。但注意标准未锁死 bool size,回答「C++ 通常 1,C 是 int 4」最稳。
六、include " " vs < > 与防重
#include <xx>:只在系统/标准 include 路径找。#include "xx":先找当前目录/用户路径,找不到再去系统路径。——便于项目内头文件。- 防重复包含:
#pragma once(MSVC/GCC 都支持,快)或传统 guard:
cpp
#ifndef FOO_H
#define FOO_H
...
#endif- 声明 vs 定义放头文件:头文件放声明、模板实现、inline、(C++17 inline 变量);不要放非 inline 的全局变量定义。
七、手写 MAX 宏的正确姿势(顺带 sizeof 面试)
cpp
// 正确写法:外层整包括号 + 参数各自括号 + 无副作用
#define MAX(a, b) ((a) > (b) ? (a) : (b))
// 副作用:MAX(++x, y) 会 ++x 两次 —— 所以能用 std::max / constexpr / inline 就别用宏