|
写C语言的语言f意思人,十有八九在某个时刻盯着一个叫 flag 的及用变量发过呆。它太常见了,语言f意思常见到很多人根本不去想它到底该叫什么、及用该怎么用。语言f意思我见过一个刚入门的及用哥们,在项目里定义了 flag1 到 flag7,语言f意思最后自己都分不清哪个是及用哪个。问题不在 flag 本身,语言f意思在于用的及用人有没有把它当回事。 flag 在C语言里不是语言f意思关键字,不是及用库函数,它就是语言f意思一个普通的变量名。直译过来是及用“旗子”,程序员用它来标记某种状态是语言f意思否成立。比如一个循环里需要判断某个条件有没有出现过,就可以设一个 int flag = 0;,出现时改成 flag = 1;,循环结束后检查这个值。就这么简单。它的本质是布尔逻辑的载体,C语言没有原生的 bool 类型(C99之前),所以早期代码大量用 int 来充当这个角色。 看一段实际代码,比任何解释都管用: #include <stdio.h> int main() { int nums[] = { 3, 7, 2, 9, 5}; int target = 9; int found = 0; // 这就是一个flag for (int i = 0; i < 5; i++) { if (nums[i] == target) { found = 1; break; } } if (found) { printf("找到了\n"); } else { printf("没找到\n"); } return 0; } 这里的 found 就是一个flag。注意我给它起的名字是 found,不是 flag。这是个习惯问题——flag 这个词太泛了,泛到几乎不传递任何信息。好的做法是用能表达具体含义的名字,比如 is_found、has_error、is_valid、need_retry。你三个月后回头看代码,found 一眼就懂,flag 得想半天。 flag的用法远不止查找。状态机里用它标记当前处于哪个阶段,解析器里用它记录是否遇到了某个特殊字符,多线程编程里用它做简单的同步标记(虽然更推荐用条件变量或原子操作)。我写过一个简单的词法分析器,里面用 in_string 这个flag来追踪是否在字符串字面量内部,遇到引号就翻转它的值。代码逻辑清晰,因为flag的名字直接对应了状态。 但flag用不好会出问题。最常见的坑是把flag当万能变量使,一个flag承担多种含义。比如有人用 flag == 0 表示未初始化,flag == 1 表示成功,flag == 2 表示失败,flag == 3 表示超时。这不是flag,这是状态码。状态码有它的用处,但别混为一谈。flag应该只有两个状态,最多加一个“未知”。超过三个值,就该考虑用枚举或者换个设计。 另一个坑是flag的作用域。全局flag能不用就不用。我调试过一个多人协作的项目,一个全局 g_flag 被四个模块读写,最后没人说得清它什么时候会变成1。局部flag安全得多,生命周期短,影响范围可控。如果确实需要跨函数传递状态,用参数传进去或者用返回值带出来,比全局变量干净。 说个具体的例子。之前帮人看一段代码,功能是检查用户输入的密码是否符合规则。代码里用了三个flag:has_upper、has_digit、has_special。每个flag独立判断,最后用逻辑与组合。这种写法就很好,每个flag职责单一,名字自解释,测试的时候也容易单独验证。反过来,如果只用一个 flag 然后赋值1、2、3、4来区分不同情况,读代码的人就得频繁翻回去看每个数字代表什么。 C99标准引入了 <stdbool.h>,可以直接用 bool、true、false。新代码建议用这个,语义更明确。int 当flag用不是不行,但 bool 更贴合意图。不过老代码里大量的 int flag 仍然在跑,读懂它们不需要什么高深技巧,只需要耐心看上下文。 最后说一句个人看法:flag本身没有好坏,关键在于命名和职责划分。一个叫 is_ready 的flag比叫 flag 的flag有价值一百倍。写代码的时候多花三秒钟想个名字,后面能省三十分钟调试时间。这笔账,怎么算都划算。 |