运算符、表达式和语句

掌握C语言运算符体系——算术/关系/逻辑/赋值/自增自减/逗号运算符,以及表达式求值与类型转换规则,能正确运用while循环构建简单程序

学习目标

  • 能正确使用算术、关系、逻辑、赋值和自增自减运算符,区分 ++i(前缀)和 i++(后缀)的表达式值差异
  • 能解释 C 语言表达式求值中的类型转换规则——整型提升、寻常算术转换和赋值转换——并预测混合类型表达式的结果
  • 能用 while 循环配合自增运算符实现一个"打印 1 到 10 及其平方值"的程序,并回答:如果把 while (n < 11) 写成 while (n <= 11),输出会多什么?

机制总览

运算符、表达式和语句:机制路径

  1. 1

    为什么 C 的运算像一条"加工流水线"?

    想象一条巧克力工厂的流水线:原料从传送带左边进来,经过混合、加热、冷却、切割、包装五道工序,右边出来的就是成品。每道工序的输入是上一道的输出,工序之间有固定的先后顺序——你先称量再混合,而不是反过来。

  2. 2

    C 运算符全览——一句话把常用运算符说清楚

    在进入细节之前,先把本章涉及的五大类运算符摊开看一遍。这张表就是你的"运算流水线机器清单"——运算符、含义、示例、优先级,一目了然:

  3. 3

    表达式与类型转换——当 int 遇上 float

    当表达式混合不同类型时,C 会按运算符规则转换操作数。 类型转换(type conversion) 需要结合类型等级和可表示范围判断。

先按顺序建立机制,再进入实验切换阶段并检查失效证据。

章级决策实验

运算符、表达式和语句:机制与证据

切换《运算符、表达式和语句》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。

选择推理阶段

当前阶段 · 为什么 C 的运算像一条"加工流水线"?

想象一条巧克力工厂的流水线:原料从传送带左边进来,经过混合、加热、冷却、切割、包装五道工序,右边出来的就是成品。每道工序的输入是上一道的输出,工序之间有固定的先后顺序——你先称量再混合,而不是反过来。

可核验证据

用 -Wall -Wextra -pedantic 构建本节示例,再以正常值、边界值和失败输入核对「为什么 C 的运算像一条"加工流水线"?」的实际行为。

学完《运算符、表达式和语句》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。

失效—证据矩阵

运算符、表达式和语句:失效与核验

为什么 C 的运算像一条"加工流水线"?

典型失效

若只记语法而忽略「为什么 C 的运算像一条"加工流水线"?」的类型范围、求值顺序或资源边界,输入变化后可能出现未定义行为或错误结果。

核验证据

用 -Wall -Wextra -pedantic 构建本节示例,再以正常值、边界值和失败输入核对「为什么 C 的运算像一条"加工流水线"?」的实际行为。

C 运算符全览——一句话把常用运算符说清楚

典型失效

若只记语法而忽略「C 运算符全览——一句话把常用运算符说清楚」的类型范围、求值顺序或资源边界,输入变化后可能出现未定义行为或错误结果。

核验证据

用 -Wall -Wextra -pedantic 构建本节示例,再以正常值、边界值和失败输入核对「C 运算符全览——一句话把常用运算符说清楚」的实际行为。

表达式与类型转换——当 int 遇上 float

典型失效

若只记语法而忽略「表达式与类型转换——当 int 遇上 float」的类型范围、求值顺序或资源边界,输入变化后可能出现未定义行为或错误结果。

核验证据

用 -Wall -Wextra -pedantic 构建本节示例,再以正常值、边界值和失败输入核对「表达式与类型转换——当 int 遇上 float」的实际行为。

每个判断都必须能落到观测、测试或产物,不能只凭代码表面推测。

为什么 C 的运算像一条"加工流水线"?

想象一条巧克力工厂的流水线:原料从传送带左边进来,经过混合、加热、冷却、切割、包装五道工序,右边出来的就是成品。每道工序的输入是上一道的输出,工序之间有固定的先后顺序——你先称量再混合,而不是反过来。

在 C 语言里,表达式由运算符和操作数组成。a + b * c 按优先级解析为 a + (b * c);这说明语法分组,不等于规定所有操作数的运行时求值先后。只有标准明确的排序规则(例如 &&||、条件运算符选中分支、逗号运算符)才能约束副作用顺序。

如果没有这套规则呢? 3 + 4 * 5 的结果可能是 35(从左算)也可能是 23(先乘后加)——同一行代码在不同机器上跑出不同答案。更可怕的是,++ii++ 如果混在一起用,你会拿到意料之外的中间值。这一章就教你掌握 C 运算流水线上每一台机器的脾气——让每个表达式都按你预想的方式出结果。

C 运算符全览——一句话把常用运算符说清楚

在进入细节之前,先把本章涉及的五大类运算符摊开看一遍。这张表就是你的"运算流水线机器清单"——运算符、含义、示例、优先级,一目了然:

C语言运算符速查表算术运算符运算符含义示例优先级+加法/正号a + b, +a-减法/负号a - b, -a*乘法a * b/除法a / b%求余(模运算)a % b关系与逻辑运算符运算符含义示例优先级< > <= >=大小关系比较a < b== !=相等/不等a == b&&逻辑与(AND)a && b||逻辑或(OR)a || b!逻辑非(NOT)!a高(一元)赋值与自增自减运算符运算符含义示例优先级=简单赋值a = 5最低+= -= *= /=复合赋值a += 3最低++i (前缀)先加后用b = ++a高(一元)i++ (后缀)先用后加b = a++高(一元)--i / i--自减(前缀/后缀)b = --a高(一元)优先级越高越先算;同级看结合律方向。一元运算符(++/--/!)优先于二元运算符。赋值(=)优先级最低。
C语言常用运算符的完整分类速查。整本书的重点不是死记优先级,而是通过括号显式控制求值顺序。

记不住没关系——全章讲完你可能只用得到括号。但理解每类运算符的语义是写出正确表达式的第一步。下面逐一拆解。

算术运算符——整数除法向零截断

看起来跟你小学数学课上的符号一样,但 C 里有两条关键差异:

  1. 整数除法向零截断,不是数学上的 floor。 5 / 2 等于 2,-5 / 2 等于 -2(C99 起明确)。除数为零或最小有符号整数除以 -1 且结果不可表示时,行为未定义。

  2. % 求余运算符只能用于整数。 10 % 3 的结果是 1——10 除以 3 商 3 余 1。% 很好记——"百分号求余,结果是除法剩下的那点不能整除的部分"。

#include <stdio.h>
int main(void) {
    printf("5 / 2   = %d\n", 5 / 2);    // 2(整数除法,截断)
    printf("5.0 / 2 = %.1f\n", 5.0 / 2); // 2.5(浮点除法)
    printf("-5 / 2  = %d\n", -5 / 2);    // -2(往零截断)
    printf("10 %% 3 = %d\n", 10 % 3);    // 1(求余)
    printf("10 %% 2 = %d\n", 10 % 2);    // 0(整除,无余数)
    return 0;
}

关系与逻辑运算符——"是真是假"的判断器

的作用是"判断条件的真假"——它们在 ifwhile 的条件里是主力。

C99 提供 _Bool<stdbool.h> 还定义 booltruefalse 宏。关系与逻辑表达式的结果类型仍是 int,值为 0 或 1;作为控制条件时,标量值 0 为假,非零为真。

#include <stdio.h>
int main(void) {
    int a = 5, b = 3;
 
    printf("a > b   = %d\n", a > b);    // 1(5 大于 3,真)
    printf("a < b   = %d\n", a < b);    // 0(5 小于 3,假)
    printf("a == 5  = %d\n", a == 5);   // 1(a 等于 5,真)
    printf("a != 5  = %d\n", a != 5);   // 0(a 等于 5,不"不等于")
 
    // 逻辑运算符:组合多个条件
    printf("a>0 && b>0  = %d\n", a > 0 && b > 0);  // 1(两边都真)
    printf("a>0 && b<0  = %d\n", a > 0 && b < 0);  // 0(一边假就全假)
    printf("a<0 || b>0  = %d\n", a < 0 || b > 0);  // 1(任一边真就真)
    printf("!(a > 0)    = %d\n", !(a > 0));         // 0(真变假)
    return 0;
}

自增自减运算符——C 语言最"狡猾"的符号

可能是 C 语言里最让人困惑的两个符号。它们都只做一件事——让变量加 1 或减 1——但前缀和后缀的区别在于表达式返回的是新值还是旧值

++i(前缀递增)—— 先加,后用i = 5++i → i=6表达式 = 6① 初始值② 先自增 +1③ 再用新值i++(后缀递增)—— 先用,后加i = 5返回旧值 5(然后 i 变 6)表达式 = 5① 初始值② 先用旧值③ i 之后变更++i = 先加再用(新值)  i++ = 先用再加(旧值)  —— 看 ++ 在变量名前还是后。
前缀递增(++i):先自增、再使用新值;后缀递增(i++):先返回旧值、再自增。二者对 i 的最终影响相同,但表达式值不同。

用代码感受一下这个差异:

#include <stdio.h>
int main(void) {
    int i = 5, j = 5;
 
    int new_i = ++i;  // 前缀:修改后产生值 6
    printf("++i: i=%d, 表达式值=%d\n", i, new_i);
 
    int old_j = j++;  // 后缀:产生旧值 5,再完成递增
    printf("j++: 表达式值=%d, j=%d\n", old_j, j);
 
    return 0;
}

赋值与复合赋值运算符

= 把右侧转换后的值存入左侧对象。 能明确表达“读取、运算、写回”:

#include <stdio.h>
int main(void) {
    int n = 10;
 
    n += 5;    // 等价于 n = n + 5;  → n 变成 15
    n -= 3;    // 等价于 n = n - 3;  → n 变成 12
    n *= 2;    // 等价于 n = n * 2;  → n 变成 24
    n /= 4;    // 等价于 n = n / 4;  → n 变成 6
    n %= 4;    // 等价于 n = n % 4;  → n 变成 2
 
    printf("n = %d\n", n);  // 输出 2
    return 0;
}

复合赋值运算符读起来也很自然:n += 5 读作"n 增加 5"。

逗号运算符——让你在一行里做多件事

, 优先级在 C 所有运算符中最低。它先求值左边的表达式(丢弃其结果),再求值右边,整个逗号表达式的结果就是最右边表达式的结果

int x, y;
x = (y = 3, y + 1);  // 先执行 y=3(y 变成 3),再计算 y+1=4
                      // x 的值是 4,y 的值是 3

最常见的用处是在 for 循环里同时初始化或更新两个变量(这是下两章的内容,先留个印象):

for (i = 0, j = 10; i < j; i++, j--) { /* ... */ }

表达式与类型转换——当 int 遇上 float

当表达式混合不同类型时,C 会按运算符规则转换操作数。 需要结合类型等级和可表示范围判断。

C 的类型转换分两阶段:

  1. 整型提升: charshort 在表达式里首先被自动提升为 int(如果 int 表示范围不够,则升为 unsigned int)。所以 char c = 'A'; c + 1 是按 int 来算的,结果是 66。

  2. 通常算术转换: 提升后若类型不同,先处理浮点等级;纯整数则比较转换等级、符号和可表示范围,选择共同类型。混合 signedunsigned 时结果尤其不能用简单“精度阶梯”概括:

C 语言类型隐式转换层次链long double扩展双精度浮点double双精度浮点float单精度浮点long长整数unsigned int无符号整数int有符号整数short短整数char字符型混合类型表达式中,低级别类型自动向高级别提升以避免数据丢失char / short 先提升为 int(整型提升)→ 再按「低→高」统一 → 赋值时反向截断(cast)赋值转换向下(窄化,可能丢数据) · 表达式求值中的隐式转换向上
C语言在表达式求值中会将低级别类型自动提升为高级别类型(整型提升 + 寻常算术转换)。赋值则反向截断,可能丢失精度。

5 / 2.05 可转换为 double,结果为 2.5;但 -1 < 1u 可能先把 -1 转为无符号类型,从而得到与直觉相反的比较结果。转换规则是语言定义的共同类型选择,不是“永不丢数据”承诺。

#include <stdio.h>
int main(void) {
    char ch = 'A';
    int  n  = 5;
    double d = 2.0;
 
    printf("ch code = %d\n", ch);            // 执行字符集中的编码值
 
    printf("n / 3  = %d\n", n / 3);         // 1(整数除法,截断)
    printf("n / d  = %.2f\n", n / d);       // 2.50(int → double,浮点除法)
    printf("n / 3.0 = %.2f\n", n / 3.0);    // 1.67(int → double,浮点除法)
 
    return 0;
}

强制类型转换——你说了算

当你需要显式地把一种类型转换成另一种类型(而不是靠 C 自动帮你做),用

int a = 5, b = 2;
double result;
 
result = a / b;              // result = 2.0(先整数除法得 2,再赋值时转为 double)
result = (double)a / b;      // result = 2.5(a 先被 cast 成 double,浮点除法)
result = (double)(a / b);    // result = 2.0(先整数除法得 2,再 cast 成 double)

强制类型转换的写法是 (目标类型)表达式(double)a / b 先把 a 转为 double(double)(a / b) 则先进行整数除法。显式写 cast 只表达意图,不会让越界转换自动变安全。

把运算符和 while 循环串起来

有了运算符基础,就可以用 while 循环来反复执行一段代码了。while 是 C 里最基本的结构之一。

while 循环流程图① 条件成立?开始② 执行循环体花括号内的代码③ 更新条件变量i++ / n-- / ...④ 回到判断退出循环菱形 = 条件判断 · 矩形 = 执行步骤 · 返回弧线 = 继续循环 · 向左分支 = 退出
while 循环的标准执行流程:先检查条件 → 条件为真执行循环体 → 更新条件变量 → 回到检查。条件为假时退出循环。

的语法很简单:

while (条件表达式) {
    // 循环体:条件为真时反复执行
    // 每次执行完回到条件检查
}

循环体如果只有一条语句,花括号 {} 可以省略,但强烈建议总是写花括号——它能防止后续添加代码时忘了加花括号而产生的 bug。

下面用 Stepper 一步步展示 while 循环如何配合自增运算符工作:

动手:while 循环一步步跑起来

猜一猜:下面这段代码运行到最后,i 的值是多少?答案不是 9!通过 Stepper 一步步揭晓。

分步1 / 4

第一步:初始化条件变量

while 循环流程图① 条件成立?开始② 执行循环体花括号内的代码③ 更新条件变量i++ / n-- / ...④ 回到判断退出循环菱形 = 条件判断 · 矩形 = 执行步骤 · 返回弧线 = 继续循环 · 向左分支 = 退出
while 循环的标准执行流程:先检查条件 → 条件为真执行循环体 → 更新条件变量 → 回到检查。条件为假时退出循环。

变量 i 先被初始化为 0。这一步只是把"计数器"归零——while 循环本身还没开始执行。i = 0 这行写在循环外面,只执行一次。确保循环前条件变量有明确的值是写出正确循环的第一步。

下面是一段完整可运行的 while 循环程序——打印 1 到 10 及其平方值:

#include <stdio.h>
int main(void) {
    int n = 1;
 
    printf("数字\t平方\n");
    printf("----\t----\n");
 
    while (n < 11) {
        printf("%d\t%d\n", n, n * n);
        n++;  // 每次循环把 n 加 1——忘了这行就死循环!
    }
 
    return 0;
}

输出:

数字  平方
----  ----
1     1
2     4
3     9
4     16
5     25
6     36
7     49
8     64
9     81
10    100

注意 while (n < 11) 这个写法——当 n = 10 时满足条件、进入循环;n 变成 11 时 11 < 11 不成立、循环结束。n <= 10n < 11 在这个场景下效果一样,但 n < 11 明确告诉你"这条循环跑到 10 为止"。

代码详解:四个核心场景逐段拆解

场景一:自增自减的完整示例——前缀 vs 后缀的全景

#include <stdio.h>
int main(void) {
    int a = 5, b = 5;
    int result;
 
    // 前缀递增:先加后用
    result = ++a;
    printf("++a: a=%d, result=%d\n", a, result);  // a=6, result=6
 
    // 后缀递增:先用后加
    result = b++;
    printf("b++: result=%d, b=%d\n", result, b);  // result=5, b=6
 
    // 单独使用时效果相同
    int x = 3, y = 3;
    ++x;
    y++;
    printf("单独使用: x=%d, y=%d\n", x, y);        // x=4, y=4
 
    return 0;
}

关键区别只在表达式有赋值或函数调用时才体现——把 ++a 的结果赋给 resultresult 得到新值 6;把 b++ 的结果赋给 resultresult 得到旧值 5。如果单独写一行 ++i;i++;,两者对 i 的效果完全一样——都让 i 加 1。 这个区别让小白很慌,但搞清楚"表达式值"和"变量值"是两个概念之后就简单了。

场景二:复合赋值——用 while 循环做累加

#include <stdio.h>
int main(void) {
    int sum = 0;
    int i = 1;
 
    while (i <= 10) {
        sum += i;  // 等价于 sum = sum + i
        i++;
    }
 
    printf("1+2+...+10 = %d\n", sum);  // 输出 55
    return 0;
}

这段代码把复合赋值和 while 循环结合起来——sum += i 每次把当前 i 的值累加到 sum 上,i++ 推动循环前进。循环体只有两行,却完成了"从 1 加到 10"的计算——运算符和循环配合得当,几行代码就能做很多事。

场景三:类型转换陷阱——赋值窄化与精度丢失

#include <stdio.h>
int main(void) {
    double pi = 3.1415926535;
    float  f  = pi;          // double → float,精度丢失
    int    n  = pi;          // double → int,小数截断
 
    printf("pi (double) = %.10f\n", pi);  // 3.1415926535
    printf("f  (float)  = %.10f\n", f);   // 3.1415927410(丢了精度!)
    printf("n  (int)    = %d\n", n);      // 3(小数全丢)
 
    // 除法中的类型差异
    printf("5/2   = %d\n", 5/2);          // 2(整数除法)
    printf("5/2.0 = %.1f\n", 5/2.0);      // 2.5(5转double,浮点除法)
    printf("5.0/2 = %.1f\n", 5.0/2);      // 2.5(2转double,浮点除法)
 
    return 0;
}

float 只有约 6-7 位有效数字——把 double 的 10 位有效数字全部塞进 float,后面的就被丢掉了。int 赋值截断更粗暴——3.99 也照样变成 3。理解了这些"数据在类型之间转移时可能被截断/丢失精度",你就能避免因为"数学上是对的但计算机上错了"而抓狂。

场景四:逗号运算符与 cast 的组合用法

#include <stdio.h>
int main(void) {
    int    i = 5;
    double d = 3.14159;
    int    result;
 
    // 逗号运算符:两个表达式顺序执行,结果是右边
    // i, i*2 的结果是 10(i*2 的值)
    printf("(i, i*2) = %d\n", (i, i * 2));  // 10
 
    // cast 运算符:显式转换
    result = (int)d;                         // double → int,截断
    printf("(int)%.5f = %d\n", d, result);   // 3
 
    // 逗号和 cast 组合
    int x;
    x = (i++, (int)(d + 0.6));              // i 先变 6,再算 (int)3.74 = 3
    printf("x = %d, i = %d\n", x, i);       // x=3, i=6
 
    return 0;
}

(i++, (int)(d + 0.6)) 这个表达式里:先用逗号让 i++ 把 i 从 5 变成 6(丢弃旧值),再算 d + 0.6 = 3.74、cast 成 (int) 得 3——整个表达式的值是 3。逗号运算符在实际中用得不多,但在 for 循环的初始化和更新段里几乎必不可少。

容易踩的坑

小结

  • C 的五大类运算符各有明确的语义:算术(含截断除法和求余)、关系与逻辑(结果是整数 1/0)、自增自减(前缀新值、后缀旧值)、复合赋值(运算+赋值缩写)、逗号(顺序执行,取最右)
  • ++i 返回新值(先加后用),i++ 返回旧值(先用后加)——单独使用时效果相同,有赋值或传参时表达式值不同
  • 混合类型表达式按整型提升 + 寻常算术转换自动升级;赋值时反向截断(窄化,可能丢数据);cast 显式控制转换
  • while 循环遵循"检查条件 → 执行循环体 → 更新条件 → 回到检查"四步;条件不成立时循环体一次都不执行
  • 最易踩的坑:同一变量多次自增自减(未定义行为)、while() 后多了分号(空循环体死循环)、= 写成 ==(赋值当比较)

练习

问题 1(改代码型) 下面程序有两处导致死循环的问题。找出并修正,再说明退出后的 n

#include <stdio.h>
int main(void) {
    int n = 1;
    while (n <= 10); {
        printf("%d^2 = %d\n", n, n * n);
    }
    printf("n 最终值 = %d\n", n);
    return 0;
}

问题 2(问答型) 写出前三行的确定结果,并说明为什么后两行都没有可移植答案。

#include <stdio.h>
int main(void) {
    int i = 3, j = 3;
 
    printf("① 5/2 = %d\n", 5 / 2);
    printf("② 5.0/2 = %.1f\n", 5.0 / 2);
    printf("③ 10%%3 = %d\n", 10 % 3);
    printf("④ ++i = %d, i = %d\n", ++i, i);
    printf("⑤ j++ = %d, j = %d\n", j++, j);
    return 0;
}

问题 3(综合实现型)while 打印 1 到 100 中的 7 的倍数,要求以 += 更新循环变量,并解释为什么不会发生有符号溢出。

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

算术运算符(arithmetic operator)

完成加减乘除和求余运算的符号:+(加/正号)、-(减/负号)、*(乘)、/(除)、%(求余/模运算)。它们和小学数学符号长得一样,但 C 里整数除法会截断(丢掉小数部分)、% 求余只能用于整数。详见本章「算术运算符」一节和 COperatorTable 速查表。

关系运算符(relational operator)

用于比较两个值大小关系的运算符:<(小于)、<=(小于等于)、>(大于)、>=(大于等于)、==(等于)、!=(不等于)。关系表达式的结果是整数:关系成立返回 1,不成立返回 0。=== 是两回事——一个是"比大小"、一个是"把值塞进去"。详见本章「关系与逻辑运算符」一节。

逻辑运算符(logical operator)

对真/假条件进行组合的运算符:&&(逻辑与,两边都真才真)、||(逻辑或,任一边真就真)、!(逻辑非,真变假、假变真)。C 里没有单独的"布尔类型"——非零就是真、0 就是假,逻辑运算符的结果也是整数 1 或 0。详见本章「关系与逻辑运算符」一节。

自增运算符(++)和自减运算符(--)

只让变量加 1 或减 1 的一元运算符。前缀(++i):先加,表达式的值是新值。后缀(i++):先返回旧值,再加。两者对变量的最终影响完全相同——单独写 i++;++i; 效果一样。只有在被赋值或当函数参数时,"表达式值"的差异才体现出来。详见本章「自增自减运算符」一节和 IncrementTimelineDiagram Stepper 图示。

复合赋值运算符

把二元运算和写回组合起来,如 +=-=*=。左操作数只求值一次,结果再转换为左侧类型,因此带副作用的左侧不能机械展开成普通赋值。

逗号运算符(comma operator)

优先级最低的二元运算符:表达式1, 表达式2。从左到右顺序求值——先算左边、丢弃结果,再算右边、以右边结果为整个表达式的结果。最常见用法是在 for 循环的初始化和更新段里同时做多件事(如 for (i=0, j=10; ...; i++, j--))。详见本章「逗号运算符」一节。

类型转换(type conversion)

值在不同类型间映射的规则,包括整数提升、通常算术转换、赋值转换和显式转换。共同类型由等级、符号和可表示范围共同决定,可能改变数值或精度。

强制类型转换(cast)

一元运算符 (目标类型)表达式,显式地把表达式的值转换成指定类型。cast 优先级很高——(double)a / b 是把 a 先转成 double 再做除法,(double)(a / b) 是先做整数除法再把结果转 double(已经丢掉的小数再转也回不来)。详见本章「强制类型转换」一节。

while 循环

C 语言的入口条件循环结构:while (条件) { 循环体 }。先检查条件→条件为真则执行循环体→回到条件检查→条件为假则退出。循环体可能一次都不执行(如果条件一开始就不成立)。条件变量必须在循环体内被更新——忘了更新就会死循环。详见本章「while 循环」一节和 WhileLoopFlowDiagram Stepper 图示。

原版目录概念补充核对

以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。

取模:机制、边界与证据

在《运算符、表达式和语句》的官方单元 cpr-05 中,取模连接本章第 3 组知识约束。学习时要同时说明它接受什么输入、改变什么状态、在何种边界失效;再以本章示例的编译诊断、固定输入输出或失败用例复核结论,不能只记术语名称。

讨论

评论区加载中…