• C Primer Plus(6) 中文版 第5章 运算符、表达式和语句 5.3 其他运算符


    5.3 其他运算符
    C语言有大约40个运算符。
    5.3.1 sizeof运算符和size_t类型
    sizeof运算符以字节为单位返回运算对象的大小(在C语言中,1字节定义为char类型占用的空间大小)。
    运算对象可以是具体的数据对象(如,变量名)或类型。如果运算对象是类型,则必须用圆括号将其括起来。
    // sizeof.c -- uses sizeof operator
    // uses C99 %z modifier -- try %u or %lu if you lack %zd
    #include
    int main(void)
    {
        int n = 0;
        size_t intsize;
        
        intsize = sizeof (int);
        printf("n = %d, n has %zd bytes; all ints have %zd bytes.\n",
               n, sizeof n, intsize );
        
        return 0;

     

    /* 输出:

    */

    C语言规定,sizeof返回size_t类型的值。这是一个无符号整数类型,但它不是新类型。前面介绍过,size_t是语言定义的标准类型。C有一个typedef机制,允许程序员为现有类型创建别名。
    typedef double real;
    编译器查看real时会发现,在typedef声明中real已成为double的别名,于是把real创建为double类型的变量。
    C99做了进一步调整,新增了%zd转换说明用于printf()显示size_t类型的值。
    5.3.2 求模运算符:%
    求模运算符(modulus operator)用于整数运算。求模运算符给出其左侧整数除以右侧整数的余数(reminder)。
    求模运算符只能用于整数,不能用于浮点数。
    求模运算符常用于控制程序流。
    // min_sec.c -- converts seconds to minutes and seconds
    #include
    #define SEC_PER_MIN 60            // seconds in a minute
    int main(void)
    {
        int sec, min, left;
        
        printf("Convert seconds to minutes and seconds!\n");
        printf("Enter the number of seconds (<=0 to quit):\n");
        scanf("%d", &sec);            // read number of seconds
        while (sec > 0)
        {
            min = sec / SEC_PER_MIN;  // truncated number of minutes
            left = sec % SEC_PER_MIN; // number of seconds left over
            printf("%d seconds is %d minutes, %d seconds.\n", sec,
                   min, left);
            printf("Enter next value (<=0 to quit):\n");
            scanf("%d", &sec);
        }
        printf("Done!\n");
        
        return 0;
    }

    /* 输出:

    */ 

    每次循环都会改变被测试的变量值。
    C99规定负数求模“趋零截断”之前,该问题的处理方法很多。但自从有了这条规则之后,如果第1个运算对象是负数,那么求模的结果是负数,那么求模的结果为负数;如果第1个运算对象是正数,那么求模的结果也是正数。
    实际上,标准规定:无论何种情况,只要a和b都是整数值,便可通过a-(a/b)*b来计算a%b。
    5.3.3 递增运算符:++
    递增运算符(increment operator)执行简单的任务,将其运算对象递增1。该运算符以两种方式出现。
    第1种方式,++出现在其作用的变量前面,这是前缀模式;
    第2种方式,++出现在其作用的变量后面,这是后缀模式;
    两种模式的区别在于递增行为发生的时间不同。
    /* add_one.c -- incrementing: prefix and postfix */
    #include
    int main(void)
    {
        int ultra = 0, super = 0;
        
        while (super < 5)
        {
            super++;
            ++ultra;
            printf("super = %d, ultra = %d \n", super, ultra);
        }
        
        return 0;

    /* 输出:

    */ 

    super = super + 1; 
    创建两个缩写形式的原因之一是:紧凑结构的代码让程序更为简洁诶,可读性更高。让程序看起来更美观。
    shoe = 2.0; //note the original shoe is 2.0, not 3.0
    while( ++shoe < 18.5 ){
        foot = SCALE * shoe + ADJUST;
        ...

    充分利用了递增运算符的优势。
    更重要的是,它把控制循环的两个过程几种在一个地方。该循环的主要过程是判断是否继续循环,次要过程是改变待测试的元素。
    如果陷入无限循环(infinite loop),只能强行关闭这个程序。把循环测试和更新测试放在一处,就不会忘记更新循环。
    但是,把两个操作合在一个表达式中,降低了代码的可读性,让代码难以理解。而且,还容易产生计数错误。
    递增运算的另一个优点是,通常它生成的机器语言代码效率更高,因为它和实际的机器语言很相似。
    /* post_pre.c -- postfix vs prefix */
    #include
    int main(void)
    {
        int a = 1, b = 1;
        int a_post, pre_b;
        
        a_post = a++;  // value of a++ during assignment phase
        pre_b = ++b;   // value of ++b during assignment phase
        printf("a  a_post   b   pre_b \n");
        printf("%1d %5d %5d %5d\n", a, a_post, b, pre_b);
        
        return 0;
    }

    /* 输出:

    */ 

    a和b都递增了1,但是a_post是a递增之前的值,而pre_b是b递增之后的值。这就是++的前缀形式和后缀形式的区别。
    单独使用递增运算符时,使用哪种形式都没关系。但是,但运算符的运算对象是更复杂表达式的一部分时,使用前缀和后缀的效果不同。
    如果使用前缀形式或者后缀形式会对代码产生不同的影响,那么最为明智的是不要那样使用它们。例如: 
    b = ++i;  //如果使用i++,会得到不同的结果
    应该使用下列语句:
    ++i; //第1行
    b=i; //如果第1行使用的是i++,并不会影响b的值。
    5.3.4 递增运算符:--
    每种形式的递增运算符都有一个递减运算符(decrement operator)与之对应,用--代替++即可。

    /* 输出:

    */ 

    顺带一提,>运算符表示“大于”,<运算符表示“小于”,它们都会关系运算符(relational operator)。 
    5.3.5 优先级
    递增和递减运算符都有很高的结合优先级,只有圆括号比它们高。递增和递减运算符只能影响一个变量(或者,更普遍地说,只能影响一个可修改的左值)。
    不要混淆这两个运算符的优先级和它们的求值顺序。 
    nextnum = (y + n++) * 6;
    根据优先级可以判断何时使用n的值对表达式求值,而递增运算符的形式决定了何时递增n的值。 
    5.3.6 不要自作聪明 
    如果一次使用太多递增运算符,自己都会糊涂。例如:
    while( num < 21 ){
        printf( "%10d %10d\n", num, num * num++ );

    这种行为是未定义的。
    在C语言中,编译器可以自行选择先对函数中的哪个参数求值。这样做提高了编译器的效率,但是如果在函数的参数中使用了递增运算符,就会有一些问题。
    该语句的问题是:编译器可能不会按照预想的顺序来执行。编译器可能先对num * num++进行求值,再对num进行求值。
    还有一种情况,也不确定:
    n = 3;
    y = n++ + n++;
    结果为n的值为5,但是y的值不确定。对于这种情况更精确地说,结果是未定义的,这意味着C标准并未定义结果应该是什么。
    遵循以下规则,很容易避免类似的问题:
    *如果一个变量出现在 一个函数的多个参数中,不要对该变量使用递增或递减运算符;
    *如果一个变量多次出现在一个表达式中,不要对该变量使用递增或递减运算符。
    另一个方面,对于何时执行递增,C还是做了一些保证。这在讨论“副作用”和“序列点”将讲解。

  • 相关阅读:
    ubuntu文件上有锁
    docker 分离engine和client
    ASEMI整流桥GBJ2510参数:拆析其关键性能特点
    试图替代 Python 的下一代AI编程语言:Mojo
    SpringBoot中使用JdbcTemplate访问Oracle数据库
    第十五章 I/O(输入/输出)流
    污水处理智能化:污水处理拓扑图的未来发展趋势
    React-Hooks怎样封装防抖和节流-面试真题
    网络安全内网渗透之信息收集--systeminfo查看电脑有无加域
    Sa-Token
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126191181