C语言入门:从算术运算到位操作

C语言运算符详解:从算术运算到位操作

C语言以其丰富的运算符系统而著称,提供了50多种不同类型的运算符,可以满足各种编程需求。运算符是程序中进行计算和逻辑判断的基础工具,理解它们的特性和优先级对于编写高效、正确的代码至关重要。本篇文章将详细讲解C语言中的各类运算符及其使用技巧。

一、算术运算符:基础数学运算

算术运算符专门用于数学计算,是编程中最常用的运算符类型。

基本算术运算符:

  • +:正值运算符(一元运算符)
  • -:负值运算符(一元运算符)
  • +:加法运算符(二元运算符)
  • -:减法运算符(二元运算符)
  • *:乘法运算符
  • /:除法运算符
  • %:余值运算符

1. 一元运算符与二元运算符

+-既可以作为一元运算符,也可以作为二元运算符:

C
1
2
3
4
5
int x = -12;        // 一元运算符-改变值的正负号
int y = +x; // 一元运算符+对值无影响,可省略

int a = 4 + 22; // 二元运算符+进行加法
int b = 61 - 23; // 二元运算符-进行减法

2. 乘法与除法运算

C
1
2
3
4
5
int num = 5;
printf("%i\n", num * num); // 输出 25

float x = 6 / 4; // 注意:整数除法结果为1.0
printf("%f\n", x); // 输出 1.000000

重要提示: C语言中的整数除法是整除运算,只会返回整数部分。要得到浮点数结果,至少有一个运算数必须是浮点数:

C
1
2
float x = 6.0 / 4;        // 或者写成 6 / 4.0
printf("%f\n", x); // 输出 1.500000

3. 求模运算

%运算符用于求两个整数相除的余值,只能用于整数运算:

C
1
2
3
4
5
6
int x = 6 % 4;      // 结果为2

// 负数求模规则:结果的正负号由第一个运算数决定
11 % -5; // 结果为1
-11 % -5; // 结果为-1
-11 % 5; // 结果为-1

4. 赋值运算简写形式

C语言提供了简写形式,将赋值运算符与算术运算符结合:

C
1
2
3
4
5
i += 3;  // 等同于 i = i + 3
i -= 8; // 等同于 i = i - 8
i *= 9; // 等同于 i = i * 9
i /= 2; // 等同于 i = i / 2
i %= 5; // 等同于 i = i % 5

二、自增与自减运算符

C语言提供专门对变量进行+1-1操作的运算符:

  • ++:自增运算符
  • --:自减运算符
C
1
2
i++;     // 等同于 i = i + 1
i--; // 等同于 i = i - 1

前置与后置的区别:

  • ++var--var:先执行自增/自减,再返回操作后的值
  • var++var--:先返回操作前的值,再执行自增/自减
C
1
2
3
4
5
int i = 42;
int j;

j = (i++ + 10); // i: 43, j: 52(先使用i的值,再自增)
j = (++i + 10); // i: 44, j: 54(先自增,再使用i的值)

最佳实践: 为避免意外结果,建议将自增/自减操作与返回值分离:

C
1
2
3
4
5
6
7
/* 写法一:先使用再自增 */
j = (i + 10);
i++;

/* 写法二:先自增再使用 */
i++;
j = (i + 10);

三、关系运算符:比较与判断

关系运算符用于比较运算数的大小关系,返回0(假)或1(真):

  • >:大于运算符
  • <:小于运算符
  • >=:大于等于运算符
  • <=:小于等于运算符
  • ==:相等运算符
  • !=:不相等运算符
C
1
2
3
4
5
6
a == b;     // 判断a是否等于b
a != b; // 判断a是否不等于b
a < b; // 判断a是否小于b
a > b; // 判断a是否大于b
a <= b; // 判断a是否小于等于b
a >= b; // 判断a是否大于等于b

重要注意事项:

  1. 避免混淆===
C
1
2
3
4
5
if (x = 3) ...     // 错误:这是赋值,不是比较
if (x == 3) ... // 正确:比较运算

// 防御性编程技巧:将常量写在左边
if (3 == x) ... // 如果误写成=,编译器会报错
  1. 避免连续使用关系运算符
C
1
2
3
4
5
// 错误写法:不会得到预期结果
i < j < k; // 实际执行:(i < j) < k

// 正确写法:使用逻辑运算符连接
i < j && j < k; // 判断j是否在i和k之间

四、逻辑运算符:复杂条件判断

逻辑运算符用于构建复杂的条件表达式:

  • !:否运算符(改变单个表达式的真伪)
  • &&:与运算符(两侧都为真时返回真)
  • ||:或运算符(两侧至少一个为真时返回真)
C
1
2
3
4
5
6
7
8
9
// 与运算符:两个条件都必须满足
if (x < 10 && y > 20) {
printf("Doing something!\n");
}

// 否运算符:需要括号确保优先级
if (!(x < 12)) {
printf("x is not less than 12\n");
}

短路求值特性:

逻辑运算符采用短路求值,如果左侧表达式的结果已经能确定整个表达式的结果,就不会计算右侧表达式:

C
1
2
3
if (number != 0 && 12/number == 2) {
// 如果number为0,不会执行12/number,避免除零错误
}

五、位运算符:二进制位操作

位运算符直接操作数据的二进制位:

1. 取反运算符~

C
1
2
// 返回 01101100
~ 10010011 // 每个位取反:0变1,1变0

2. 与运算符&

C
1
2
3
4
5
// 返回 00010001
10010011 & 00111101 // 对应位都为1时返回1

// 简写形式
val &= 0377; // 等同于 val = val & 0377

3. 或运算符|

C
1
2
3
4
// 返回 10111111
10010011 | 00111101 // 对应位有一个为1就返回1

val |= 0377; // 简写形式

4. 异或运算符^

C
1
2
3
4
// 返回 10101110
10010011 ^ 00111101 // 对应位有且仅有一个为1时返回1

val ^= 0377; // 简写形式

5. 左移运算符<<

C
1
2
3
4
// 1000101000
10001010 << 2 // 向左移动两位,尾部补0

val <<= 2; // 简写形式,相当于乘以4

6. 右移运算符>>

C
1
2
3
4
// 返回 00100010
10001010 >> 2 // 向右移动两位,头部补0

val >>= 2; // 简写形式,相当于除以4

注意: 右移运算符最好只用于无符号整数,不同系统对负数右移的处理可能不同。

六、逗号运算符:多表达式组合

逗号运算符用于将多个表达式组合在一起,按顺序执行:

C
1
2
3
4
x = 10, y = 20;     // 依次执行两个赋值语句

int x;
x = (1, 2, 3); // 返回最后一个表达式的值,x等于3

七、运算优先级:执行顺序规则

运算符优先级决定了表达式中各运算符的执行顺序:

C
1
2
3
3 + 4 * 5;          // 先计算4*5,再计算3+20,结果为23

5 * 6 / 2; // 优先级相同,左结合:先5*6,再30/2

部分运算符优先级(从高到低):

  1. 圆括号()
  2. 自增++、自减--
  3. 一元运算符+-
  4. 乘法*、除法/
  5. 加法+、减法-
  6. 关系运算符<>
  7. 赋值运算符=

最佳实践: 多用圆括号明确运算顺序,提高代码可读性:

C
1
int x = (3 + 4) * 5;    // 明确指定加法先于乘法

总结

C语言的运算符系统功能强大但规则复杂,掌握各类运算符的特性和优先级是编写高质量代码的基础。关键要点:

  1. 算术运算注意整数除法的特性,合理使用浮点数
  2. 自增自减理解前置后置的区别,避免复杂表达式中的意外
  3. 关系比较严格区分===,避免连续比较
  4. 逻辑运算利用短路特性优化代码,注意运算符优先级
  5. 位运算理解二进制操作原理,谨慎处理有符号数
  6. 优先级多用圆括号明确意图,减少依赖记忆

通过系统学习和实践,你将能够熟练运用C语言的各种运算符,编写出更加高效、可靠的程序。


C语言入门:从算术运算到位操作
https://www.edenzeng.online/2015/10/09/0.技术栈/01.开发语言/01.C语言/03-运算符详解/
作者
Edenzeng
发布于
2015年10月9日
许可协议