我处理 if (i = 常量) 这类错误的办法:前期先“常量在前”,后期再交给 IDE

我在人间做废物 发布于 2026-03-15 281 次阅读


写 C/C++ 时,有一类错误特别典型:

if (i = 3)
{
    // ...
}

本来想写的是:

if (i == 3)
{
    // ...
}

但手一快,就把 == 写成了 =。麻烦的是,这种代码在 C/C++ 里往往不是语法错误,它通常还能编译,因为赋值表达式本身有值,放进条件里是合法的。MSVC 对这种情况对应的就是 C4706:assignment used as a condition。而且这条警告是 4 级警告,需要开到 /W4 才能稳定看到;Visual Studio IDE 的默认警告级别通常是 /W3。

所以我对这个问题的态度一直都不是二选一,而是分阶段处理:

前期我更推荐直接写成“常量在前”,先把低级手滑错误按住;
后期再逐步过渡到更自然的写法,同时把 Visual Studio 的警告、错误提升和代码分析全开起来。这样既实用,也更符合长期工程化开发。

一、我为什么前期推荐“常量在前”

我前期更愿意写:

if (3 == i)
{
}

原因很简单。这样一来,哪怕手滑写成:

if (3 = i)
{
}

编译器也会直接报错,因为常量不能作为赋值左值。

这不是最优雅的长期风格,但对刚开始写条件判断的人来说,它确实有防呆效果。相比“读起来是不是最自然”,我更在意前期先别把最常见、最隐蔽的错误写进去。毕竟 if (i = 3) 这种问题最烦的地方就在于:它常常不是编不过,而是编得过、跑得动、结果还错。MSVC 官方对 C4706 的说明也很明确:如果本意是比较关系,就应该写 ==,不是 =。

二、我不把“常量在前”当成最终风格

虽然我前期推荐这么写,但我不觉得这应该成为永久规范。

因为代码写久了以后,绝大多数人读起来更自然的还是:

if (i == 3)
{
}

这更符合正常的阅读顺序:判断变量 i 是否等于 3。反过来写成 3 == i,虽然能防手滑,但长期看可读性一般,也不算现代 C++ 工程里最理想的表达方式。真正成熟的做法,应该是正常写代码,然后把工具链配置好,让 IDE 和编译器帮我拦这类错误。微软也明确建议尽量在最高的常规警告级别 /W4 下编译。

三、我的过渡路线:从写法防错,慢慢过渡到工具防错

我的思路一直很明确:

前期先靠写法防错,先写:

if (3 == i)
{
}

等对 = 和 == 足够敏感之后,再逐步回到自然写法:

if (i == 3)
{
}

与此同时,把 Visual Studio 的警告、错误处理和代码分析一起配好。这样后面靠的就不再是“绕一下写法”,而是靠一套更稳定的开发环境来兜底。

四、我在 Visual Studio 里怎么配

1. 先把警告等级开到 /W4

我一般会到:

项目 -> 属性 -> 配置属性 -> C/C++ -> 常规 -> Warning Level

把它设成:

Level4 (/W4)

因为 C4706 本身就是 level 4 warning。不开到 /W4,这类问题很可能根本不提醒。微软文档对 /W0 到 /W4 的说明里也写得很清楚:IDE 默认通常是 /W3,而 /W4 会打开更多高价值警告。

2. 再把警告视为错误

接着我会把:

项目 -> 属性 -> 配置属性 -> C/C++ -> 常规 -> Treat Warnings as Errors

设为开启,也就是 /WX。

这样做的意义非常直接:
只要这类问题出现,就别让我继续往下编译。微软文档也说明了 /WX 会把警告按错误处理;一旦这么做,带有警告的编译会直接失败。

3. 需要的话,再单独把 4706 升格

如果项目里历史包袱比较多,不想一下子把所有警告都变成错误,我也会只针对这一类问题下手,直接用 /we4706,也就是只把 4706 当成错误处理。MSVC 的 warning-level 选项支持这种按编号提升的方式。

4. 再把代码分析打开

我还会打开:

项目 -> 属性 -> 配置属性 -> Code Analysis

微软文档里给出的路径就是在项目属性页里进入 Code Analysis 页面,可以开启 Microsoft Code Analysis,也可以配置为构建时自动运行。

这一步的价值在于,它不只是从“编译器警告”的角度看问题,还会从“代码缺陷”的角度再扫一遍。像把常量赋给变量再放进布尔测试上下文这种情况,代码分析对应的就是 C6282。微软对这条规则的描述也很直接:在测试上下文中把常量赋给变量,几乎总是错的,应该把 = 改成 ==。

五、我现在更认同的写法和做法

所以我现在的结论很简单:

前期我推荐先用“常量在前”:

if (3 == i)
{
}

这不是因为它最优雅,而是因为它对压制低级手滑真的有用。

后期我会慢慢过渡到自然写法:

if (i == 3)
{
}

然后把主要防线交给这些东西:

  • /W4
  • /WX
  • 必要时 /we4706
  • Microsoft Code Analysis
  • 构建时自动运行代码分析

这样做的好处是,代码风格可以逐步回归自然,开发习惯也会越来越工程化。

六、顺手补一句:真的想在条件里赋值怎么办

有时候条件里赋值不是手滑,而是故意的,比如一些传统写法会这么写:

while ((ch = getchar()) != EOF)
{
}

MSVC 官方对 C4706 的说明是:如果赋值确实是有意为之,就应该把它写得足够明确,比如放进括号里,或者显式再去比较非零、非空。Visual Studio 2022 近年的改进里也提到,编译器现在会识别“我故意用括号包住赋值”的这种写法,并据此抑制 C4706。

结语

我对这个问题的看法一直都不极端。

“常量在前”不是我心里最理想的长期风格,但它对前期防手滑确实有效;
而 IDE 警告和代码分析,才是我更认可的长期方案。

所以我更认同的路线不是非此即彼,而是分阶段:

先用“常量在前”减少低级错误,
再慢慢过渡到 i == 常量 的自然写法,
最后把防错这件事真正交给 Visual Studio 的警告系统和代码分析。这样走下来,代码风格、开发习惯和工程意识,都会更顺。

在代码与现实之间反复穿行的人。习惯用作品表达自己,也希望留下真正属于自己的东西
最后更新于 2026-06-13