为何MISRA C禁止修改函数形参但MISRA C++却允许?
为什么C++也应当禁止修改函数形参
MISRA C的现有规则
MISRA C规则17.8明确禁止在函数体内修改函数形参,这条规则的制定初衷很直接:C语言初学者经常会误解形参修改的实际语义,以为函数内改形参会影响调用方传入的原值。
MISRA C++的规则缺口
但MISRA C中并没有对应规则。实际上,“不要修改函数形参”这条实践准则在C里反而更有必要——C++支持引用传递,被调用函数可以直接修改调用方作用域的变量,很多时候形参列表里差一个&,就会导致完全相反的逻辑,甚至引发灾难性故障。
引用传递的预期行为
和C语言不同,C++里如果形参是引用类型,修改形参确实会同步修改调用方的原值,比如下面的代码逻辑是完全符合预期的:
void g(int32_t& x){ if (x == 42) { x = 43; // 修改x避免触发后续崩溃逻辑 } do_something(x); } void g_caller(void) { int32_t x = get_value(); g(x); if (x == 42) { crash_and_burn(); } }
这段代码里,g接收x的引用,函数内把值为42的x改成43,调用方拿到的x也会变成43,不会触发crash_and_burn()。
值传递的隐蔽陷阱
如果把形参的引用符&去掉,变成值传递,行为就和C语言完全一致:函数内对形参的修改只会作用于本地副本,调用方完全感知不到。就这一个符号的差异,就会直接导致代码触发崩溃。
这类bug的诱因非常多,根本不是只有新手会踩:
- 开发者是不是故意写逻辑要触发崩溃?
- 是不是写代码时没注意当前形参是值传递,误以为修改会同步到外部?
- 会不会是早期版本里
x是引用传递,后续接口迭代改成了值传递,开发者只记得要在函数里改x防崩溃,没注意接口已经变了?
很多有经验的C++开发者也会在这个点上翻车。对应的值传递错误代码如下:
void g(int32_t x){ if (x == 42) { x = 43; // 仅修改本地副本,调用方的x不会变化 } do_something(x); } void g_caller(void) { int32_t x = get_value(); g(x); if (x == 42) { crash_and_burn(); // 必然触发,和预期逻辑完全相反 } }
内容的提问来源于stack exchange,提问作者skyking
相关产品推荐
相关产品推荐

