Skip to content

运算符

运算符用于执行各种运算操作。C语言提供了丰富的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符等。本章将详细介绍C语言中的各类运算符。

算术运算符

c
/*
 * 算术运算符
 */

#include <stdio.h>

int main(void)
{
    int a = 10, b = 3;
    
    /* 加法运算 */
    printf("a + b = %d\n", a + b);  /* 13 */
    
    /* 减法运算 */
    printf("a - b = %d\n", a - b);  /* 7 */
    
    /* 乘法运算 */
    printf("a * b = %d\n", a * b);  /* 30 */
    
    /* 除法运算 */
    printf("a / b = %d\n", a / b);  /* 3(整数除法,截断小数) */
    
    /* 取模运算(求余数) */
    printf("a %% b = %d\n", a % b);  /* 1 */
    
    /* 浮点数除法 */
    float fa = 10.0f, fb = 3.0f;
    printf("fa / fb = %f\n", fa / fb);  /* 3.333333 */
    
    /* 注意:取模运算只能用于整数 */
    /* printf("%f", 10.0 % 3.0); */  /* 错误 */
    
    /* 负数取模 */
    printf("-10 %% 3 = %d\n", -10 % 3);   /* -1 */
    printf("10 %% -3 = %d\n", 10 % -3);   /* 1 */
    printf("-10 %% -3 = %d\n", -10 % -3); /* -1 */
    
    return 0;
}

自增自减运算符

c
/*
 * 自增自减运算符
 */

#include <stdio.h>

int main(void)
{
    int a = 5;
    int b;
    
    /* 前置自增:先加1,再使用 */
    b = ++a;
    printf("++a: a = %d, b = %d\n", a, b);  /* a=6, b=6 */
    
    /* 后置自增:先使用,再加1 */
    a = 5;  /* 重置a的值 */
    b = a++;
    printf("a++: a = %d, b = %d\n", a, b);  /* a=6, b=5 */
    
    /* 前置自减:先减1,再使用 */
    a = 5;
    b = --a;
    printf("--a: a = %d, b = %d\n", a, b);  /* a=4, b=4 */
    
    /* 后置自减:先使用,再减1 */
    a = 5;
    b = a--;
    printf("a--: a = %d, b = %d\n", a, b);  /* a=4, b=5 */
    
    /* 复杂表达式中的自增自减 */
    int x = 3;
    int y = x++ + ++x;  /* 未定义行为,应避免 */
    printf("x = %d, y = %d\n", x, y);
    
    /* 推荐写法:分开写 */
    x = 3;
    int temp1 = x;
    x++;
    int temp2 = x;
    x++;
    y = temp1 + temp2;
    printf("推荐写法: x = %d, y = %d\n", x, y);
    
    return 0;
}

关系运算符

c
/*
 * 关系运算符(比较运算符)
 */

#include <stdio.h>
#include <stdbool.h>  /* C99布尔类型 */

int main(void)
{
    int a = 10, b = 5;
    
    /* 大于 */
    printf("a > b: %d\n", a > b);   /* 1(真) */
    
    /* 小于 */
    printf("a < b: %d\n", a < b);   /* 0(假) */
    
    /* 大于等于 */
    printf("a >= b: %d\n", a >= b); /* 1 */
    
    /* 小于等于 */
    printf("a <= b: %d\n", a <= b); /* 0 */
    
    /* 等于 */
    printf("a == b: %d\n", a == b); /* 0 */
    
    /* 不等于 */
    printf("a != b: %d\n", a != b); /* 1 */
    
    /* 注意:== 和 = 的区别 */
    int x = 5;
    if (x = 10) {  /* 这是赋值,不是比较! */
        printf("x被赋值为10\n");
    }
    
    /* 正确的比较 */
    x = 5;
    if (x == 10) {
        printf("x等于10\n");
    } else {
        printf("x不等于10\n");
    }
    
    /* 推荐写法:常量放左边 */
    if (10 == x) {  /* 如果写成 10 = x 会编译错误 */
        printf("x等于10\n");
    }
    
    return 0;
}

逻辑运算符

c
/*
 * 逻辑运算符
 */

#include <stdio.h>
#include <stdbool.h>

int main(void)
{
    /* 逻辑与(&&):两个都为真才为真 */
    printf("1 && 1 = %d\n", 1 && 1);  /* 1 */
    printf("1 && 0 = %d\n", 1 && 0);  /* 0 */
    printf("0 && 1 = %d\n", 0 && 1);  /* 0 */
    printf("0 && 0 = %d\n", 0 && 0);  /* 0 */
    
    /* 逻辑或(||):有一个为真就为真 */
    printf("\n1 || 1 = %d\n", 1 || 1);  /* 1 */
    printf("1 || 0 = %d\n", 1 || 0);  /* 1 */
    printf("0 || 1 = %d\n", 0 || 1);  /* 1 */
    printf("0 || 0 = %d\n", 0 || 0);  /* 0 */
    
    /* 逻辑非(!):真变假,假变真 */
    printf("\n!1 = %d\n", !1);  /* 0 */
    printf("!0 = %d\n", !0);  /* 1 */
    
    /* 短路求值 */
    int a = 5, b = 0;
    
    /* && 短路:如果左边为假,右边不计算 */
    if (b != 0 && a / b > 1) {
        printf("不会执行这里\n");
    } else {
        printf("短路避免了除零错误\n");
    }
    
    /* || 短路:如果左边为真,右边不计算 */
    if (a > 0 || b++ > 0) {
        printf("a > 0为真,b++不执行\n");
    }
    printf("b = %d(仍然是0)\n", b);
    
    /* 实际应用 */
    int age = 25;
    int has_id = 1;
    
    /* 检查是否满足条件 */
    if (age >= 18 && has_id) {
        printf("可以进入\n");
    }
    
    return 0;
}

位运算符

c
/*
 * 位运算符
 */

#include <stdio.h>

void print_binary(int num)
{
    /* 打印整数的二进制表示 */
    for (int i = 31; i >= 0; i--) {
        printf("%d", (num >> i) & 1);
        if (i % 4 == 0 && i != 0) {
            printf(" ");
        }
    }
    printf("\n");
}

int main(void)
{
    unsigned int a = 12;  /* 二进制: 0000 1100 */
    unsigned int b = 10;  /* 二进制: 0000 1010 */
    
    printf("a = %u (二进制: ", a);
    print_binary(a);
    printf("b = %u (二进制: ", b);
    print_binary(b);
    
    /* 按位与(&):两位都为1才为1 */
    printf("\na & b = %u (二进制: ", a & b);  /* 8 (0000 1000) */
    print_binary(a & b);
    
    /* 按位或(|):有一位为1就为1 */
    printf("a | b = %u (二进制: ", a | b);   /* 14 (0000 1110) */
    print_binary(a | b);
    
    /* 按位异或(^):两位不同为1,相同为0 */
    printf("a ^ b = %u (二进制: ", a ^ b);   /* 6 (0000 0110) */
    print_binary(a ^ b);
    
    /* 按位取反(~):0变1,1变0 */
    printf("~a = %u (二进制: ", ~a);
    print_binary(~a);
    
    /* 左移(<<):左移n位,相当于乘以2^n */
    printf("\na << 2 = %u (二进制: ", a << 2);  /* 48 (0011 0000) */
    print_binary(a << 2);
    
    /* 右移(>>):右移n位,相当于除以2^n */
    printf("a >> 2 = %u (二进制: ", a >> 2);   /* 3 (0000 0011) */
    print_binary(a >> 2);
    
    /* 位运算应用 */
    printf("\n=== 位运算应用 ===\n");
    
    /* 判断奇偶 */
    int num = 7;
    if (num & 1) {
        printf("%d 是奇数\n", num);
    } else {
        printf("%d 是偶数\n", num);
    }
    
    /* 交换两个数(不使用临时变量) */
    int x = 5, y = 10;
    printf("交换前: x = %d, y = %d\n", x, y);
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
    printf("交换后: x = %d, y = %d\n", x, y);
    
    /* 设置某位为1 */
    unsigned int flags = 0;  /* 0000 0000 */
    flags = flags | (1 << 3);  /* 设置第3位为1 */
    printf("设置第3位: %u\n", flags);  /* 8 */
    
    /* 清除某位为0 */
    flags = flags & ~(1 << 3);  /* 清除第3位 */
    printf("清除第3位: %u\n", flags);  /* 0 */
    
    /* 检查某位是否为1 */
    flags = 12;  /* 0000 1100 */
    if (flags & (1 << 2)) {
        printf("第2位是1\n");
    }
    
    return 0;
}

赋值运算符

c
/*
 * 赋值运算符
 */

#include <stdio.h>

int main(void)
{
    int a = 10;  /* 基本赋值 */
    printf("a = %d\n", a);
    
    /* 复合赋值运算符 */
    
    /* 加法赋值 */
    a += 5;   /* 等价于 a = a + 5 */
    printf("a += 5: %d\n", a);  /* 15 */
    
    /* 减法赋值 */
    a -= 3;   /* 等价于 a = a - 3 */
    printf("a -= 3: %d\n", a);  /* 12 */
    
    /* 乘法赋值 */
    a *= 2;   /* 等价于 a = a * 2 */
    printf("a *= 2: %d\n", a);  /* 24 */
    
    /* 除法赋值 */
    a /= 4;   /* 等价于 a = a / 4 */
    printf("a /= 4: %d\n", a);  /* 6 */
    
    /* 取模赋值 */
    a %= 4;   /* 等价于 a = a % 4 */
    printf("a %%= 4: %d\n", a);  /* 2 */
    
    /* 位运算赋值 */
    a = 12;
    
    /* 按位与赋值 */
    a &= 10;  /* 等价于 a = a & 10 */
    printf("a &= 10: %d\n", a);  /* 8 */
    
    /* 按位或赋值 */
    a |= 5;   /* 等价于 a = a | 5 */
    printf("a |= 5: %d\n", a);   /* 13 */
    
    /* 按位异或赋值 */
    a ^= 7;   /* 等价于 a = a ^ 7 */
    printf("a ^= 7: %d\n", a);   /* 10 */
    
    /* 左移赋值 */
    a <<= 2;  /* 等价于 a = a << 2 */
    printf("a <<= 2: %d\n", a);  /* 40 */
    
    /* 右移赋值 */
    a >>= 1;  /* 等价于 a = a >> 1 */
    printf("a >>= 1: %d\n", a);  /* 20 */
    
    /* 连续赋值 */
    int b, c;
    a = b = c = 5;  /* 从右向左赋值 */
    printf("a = %d, b = %d, c = %d\n", a, b, c);
    
    return 0;
}

条件运算符

c
/*
 * 条件运算符(三元运算符)
 */

#include <stdio.h>

int main(void)
{
    int a = 10, b = 5;
    
    /* 基本语法:条件 ? 表达式1 : 表达式2 */
    /* 条件为真返回表达式1,否则返回表达式2 */
    
    int max = (a > b) ? a : b;
    printf("最大值: %d\n", max);
    
    int min = (a < b) ? a : b;
    printf("最小值: %d\n", min);
    
    /* 判断奇偶 */
    int num = 7;
    printf("%d%s\n", num, (num % 2 == 0) ? "偶数" : "奇数");
    
    /* 求绝对值 */
    int x = -5;
    int abs_x = (x >= 0) ? x : -x;
    printf("|%d| = %d\n", x, abs_x);
    
    /* 嵌套条件运算符 */
    int score = 75;
    char grade;
    
    grade = (score >= 90) ? 'A' :
            (score >= 80) ? 'B' :
            (score >= 70) ? 'C' :
            (score >= 60) ? 'D' : 'F';
    
    printf("分数 %d 的等级: %c\n", score, grade);
    
    /* 与if-else对比 */
    /* 等价的if-else写法 */
    if (score >= 90) {
        grade = 'A';
    } else if (score >= 80) {
        grade = 'B';
    } else if (score >= 70) {
        grade = 'C';
    } else if (score >= 60) {
        grade = 'D';
    } else {
        grade = 'F';
    }
    
    return 0;
}

逗号运算符

c
/*
 * 逗号运算符
 */

#include <stdio.h>

int main(void)
{
    int a, b, c;
    
    /* 逗号运算符:从左到右依次执行,返回最后一个表达式的值 */
    a = (b = 3, c = 5, b + c);
    printf("a = %d, b = %d, c = %d\n", a, b, c);  /* a=8, b=3, c=5 */
    
    /* 在for循环中使用 */
    int sum = 0;
    for (int i = 1, j = 10; i <= j; i++, j--) {
        sum += i + j;
    }
    printf("sum = %d\n", sum);
    
    /* 注意:逗号运算符的优先级最低 */
    int x = 3;
    int y = (x + 1, x + 2, x + 3);  /* y = x + 3 = 6 */
    printf("y = %d\n", y);
    
    /* 与逗号分隔符的区别 */
    int arr[] = {1, 2, 3};  /* 这里的逗号是分隔符,不是运算符 */
    printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n", arr[0], arr[1], arr[2]);
    
    return 0;
}

sizeof运算符

c
/*
 * sizeof运算符
 */

#include <stdio.h>

int main(void)
{
    /* sizeof用于基本类型 */
    printf("sizeof(char) = %zu\n", sizeof(char));
    printf("sizeof(int) = %zu\n", sizeof(int));
    printf("sizeof(double) = %zu\n", sizeof(double));
    
    /* sizeof用于变量 */
    int a = 10;
    printf("sizeof(a) = %zu\n", sizeof(a));
    printf("sizeof a = %zu\n", sizeof a);  /* 变量可以不加括号 */
    
    /* sizeof用于数组 */
    int arr[10];
    printf("sizeof(arr) = %zu\n", sizeof(arr));  /* 整个数组的大小 */
    printf("数组元素个数 = %zu\n", sizeof(arr) / sizeof(arr[0]));
    
    /* sizeof用于表达式 */
    printf("sizeof(a + 1.5) = %zu\n", sizeof(a + 1.5));  /* double的大小 */
    
    /* sizeof用于指针 */
    int *ptr;
    printf("sizeof(ptr) = %zu\n", sizeof(ptr));  /* 指针的大小 */
    
    /* sizeof返回size_t类型 */
    size_t size = sizeof(int);
    printf("size_t类型的大小: %zu\n", sizeof(size_t));
    
    return 0;
}

运算符优先级

c
/*
 * 运算符优先级和结合性
 */

#include <stdio.h>

int main(void)
{
    /* 优先级从高到低排列:
     * 1. () [] -> .                           从左到右
     * 2. ! ~ ++ -- + - * & sizeof (类型)      从右到左
     * 3. * / %                                从左到右
     * 4. + -                                  从左到右
     * 5. << >>                                从左到右
     * 6. < <= > >=                            从左到右
     * 7. == !=                                从左到右
     * 8. &                                    从左到右
     * 9. ^                                    从左到右
     * 10. |                                   从左到右
     * 11. &&                                  从左到右
     * 12. ||                                  从左到右
     * 13. ?:                                  从右到左
     * 14. = += -= *= /= %= &= ^= |= <<= >>=   从右到左
     * 15. ,                                   从左到右
     */
    
    int a = 5, b = 3, c = 2;
    int result;
    
    /* 乘除优先于加减 */
    result = a + b * c;
    printf("a + b * c = %d\n", result);  /* 5 + 6 = 11 */
    
    /* 使用括号改变优先级 */
    result = (a + b) * c;
    printf("(a + b) * c = %d\n", result);  /* 8 * 2 = 16 */
    
    /* 关系运算符优先于逻辑运算符 */
    if (a > b && b > c) {
        printf("a > b > c\n");
    }
    
    /* 赋值运算符优先级很低 */
    int x, y, z;
    x = y = z = 0;  /* 从右到左赋值 */
    printf("x = %d, y = %d, z = %d\n", x, y, z);
    
    /* 复杂表达式 */
    result = a + b > c && b != c || a < c;
    /* 等价于: ((a + b) > c) && (b != c) || (a < c) */
    printf("result = %d\n", result);
    
    /* 建议:使用括号明确优先级 */
    result = ((a + b) > c) && ((b != c) || (a < c));
    printf("使用括号: result = %d\n", result);
    
    return 0;
}

类型转换运算符

c
/*
 * 类型转换运算符
 */

#include <stdio.h>

int main(void)
{
    /* 隐式类型转换 */
    int a = 5;
    double b = 2.5;
    double c = a + b;  /* int自动转换为double */
    printf("隐式转换: %f\n", c);
    
    /* 显式类型转换(强制转换) */
    int x = 5, y = 2;
    
    /* 整数除法 */
    int int_result = x / y;
    printf("整数除法: %d\n", int_result);  /* 2 */
    
    /* 浮点除法 */
    double float_result = (double)x / y;
    printf("浮点除法: %f\n", float_result);  /* 2.5 */
    
    /* 截断小数 */
    double d = 3.7;
    int i = (int)d;
    printf("截断: %d\n", i);  /* 3 */
    
    /* 四舍五入 */
    int rounded = (int)(d + 0.5);
    printf("四舍五入: %d\n", rounded);  /* 4 */
    
    /* 指针类型转换 */
    int num = 0x41424344;
    char *ptr = (char *)&num;
    printf("指针转换: %c\n", ptr[0]);  /* 取决于字节序 */
    
    return 0;
}

小结

本章学习了:

  • 算术运算符:+、-、*、/、%、++、--
  • 关系运算符:>、<、>=、<=、==、!=
  • 逻辑运算符:&&、||、!
  • 位运算符:&、|、^、~、<<、>>
  • 赋值运算符:=、+=、-=、*=、/=、%=等
  • 条件运算符:?:
  • 逗号运算符:,
  • sizeof运算符:获取大小
  • 运算符优先级:使用括号明确优先级

下一章,我们将学习流程控制,了解C语言的条件语句和循环语句。