• C puzzles详解【13-15题】


    第十三题

      int CountBits(unsigned int x)
      {
          int count=0;
          while(x)
          {
              count++;
              x = x&(x-1);
          }
          return count;
      }

    知识点讲解

    • 位运算

    关于位运算的一些例子参考:

    http://www.ugcs.caltech.edu/~wnoise/base2.html

    题目讲解

    x&(x-1)常见的两种应用:

    1)计算x二进制形式中1的个数,每循环一次,将x二进制形式最右边的1变成0;

    2)判断x是否是2的幂,若x&(x-1)==0,x为2的幂。

    第十四题

    Are the following two function prototypes same? 
      int foobar(void);
      int foobar();
    The following programs should be of some help in finding the answer: (Compile and run both the programs and see what happens) 
    Program 1: 
      #include <stdio.h>
      void foobar1(void)
      {
       printf("In foobar1
    ");
      }
    
      void foobar2()
      {
       printf("In foobar2
    ");
      }
    
      int main()
      {
         char ch = 'a';
         foobar1();
         foobar2(33, ch);
         return 0;
      }
    Program 2: 
      #include <stdio.h>
      void foobar1(void)
      {
       printf("In foobar1
    ");
      }
    
      void foobar2()
      {
       printf("In foobar2
    ");
      }
    
      int main()
      {
         char ch = 'a';
         foobar1(33, ch);
         foobar2();
         return 0;
      }

    知识点讲解

    • foo()和foo(void)是不一样的

    调用foo()时,可以传入任意个数,任意类型的参数,编译器不会关心传给foo的参数,传入的参数对foo函数的执行没有影响;

    调用foo(void)时,不可传入参数,否则编译不通过;

    void foo() {}是定义无参数函数的一种过时的用法,故日常编写代码时,若函数没有参数,最好写成foo(void)的形式。

    题目讲解

    Program 1能编译通过,运行后正常打印两个字符串;

    Program 2编译不通过,提示foobar1参数过多。

    第十五题

    What's the output of the following program and why? 
      #include <stdio.h>
      int main()
      {
       float a = 12.5;
       printf("%d
    ", a);
       printf("%d
    ", *(int *)&a);
       return 0;
      }

    知识点讲解

    • printf中的%f读取sizeof(double)个字节;
    #include <stdio.h>
    
    int main()
    {
            int a = 10, b = 20, c = 30;
            printf("%f, %d
    ", a, b, c);
            return 0;
    }

    输出:0.000000, 30

    调用printf时,双引号后面的所有参数从右往左依次入栈,然后将栈中的数据根据双引号中的格式从低地址向高地址依次读取并打印出来。

    上述代码调用printf时,c,b,a依次入栈,%f读取sizeof(double)=8个字节,

    即a,b所占的区域,转换成浮点数为0.000000,%d继续读取下面4个字节,即c所占的区域,转换为整型数为30。

    • printf中传入的float型参数自动转换成double型;
    #include <stdio.h>
    
    int main()
    {
            float a = 1.2;
            int b = 10;
            printf("%x, %x, %d
    ", a, b);
            return 0;
    }

    输出:40000000, 3ff33333, 10

    调用printf时,参数a被转为double型后再传入printf,printf的前两个%x读取的是a所占的8个字节,%d读取的是b所占的4个字节。

    gcc –S test.c命令可以生成汇编代码,上例的汇编代码主体如下:

    main:
            pushl   %ebp
            movl    %esp, %ebp
            andl    $-16, %esp
            subl    $32, %esp
            movl    $0x3f99999a, %eax
            movl    %eax, 28(%esp)
            movl    $10, 24(%esp)
            flds    28(%esp)
            movl    $.LC1, %eax
            movl    24(%esp), %edx
            movl    %edx, 12(%esp)
            fstpl   4(%esp)
            movl    %eax, (%esp)
            call    printf
            movl    $0, %eax
            leave
            ret

    “flds    28(%esp)”,flds将28(%esp)地址处的单精度浮点数即0x3f99999a加载到浮点寄存器,“fstpl   4(%esp)”即将浮点寄存器中的浮点数转换成double型后放到4(%esp)处。

    • printf中的%c读取4个字节,printf的char型参数先转换为int再入栈;
    #include <stdio.h>
    
    int main()
    {
            char a = 97;
            int b = 20;
            printf("%c, %d
    ", a, b);
            return 0;
    }

    输出:a, 20

    上述c代码的汇编代码主体为:

    main:
            pushl   %ebp
            movl    %esp, %ebp
            andl    $-16, %esp
            subl    $32, %esp
            movb    $97, 31(%esp)
            movl    $20, 24(%esp)
            movsbl  31(%esp), %edx
            movl    $.LC0, %eax
            movl    24(%esp), %ecx
            movl    %ecx, 8(%esp)
            movl    %edx, 4(%esp)
            movl    %eax, (%esp)
            call    printf
            movl    $0, %eax
            leave
            ret

    “movl    %edx, 4(%esp)”在栈中压了4个字节。

    • sizeof(‘a’)=4;
    #include <stdio.h>
    
    int main()
    {
            char a = 'a';
            printf("%d, %d
    ", sizeof(a), sizeof('a'));
            return 0;
    }

    sizeof求类型的大小,sizeof(a)即sizeof(char),sizeof(‘a’)即sizeof(int),‘a’自动转换为int型。

    题目讲解

    “printf("%d ", a);”,a转换为double型再入栈,%d读取double型数据的低4个字节;

    “printf("%d ", *(int *)&a);”float占4个字节,*(int *)&a将a在内存中存放值转换为整型数后再传入printf。

    浮点数在内存中如何表示参考第九题讲解。

  • 相关阅读:
    多线程和异步
    Win7 系统证书链错误
    应用项目迁移到 dotnet 6 的经验和决策
    工具大全(自动化、接口、性能、安全、测试管理)
    从零搭建 Npm 包持续集成
    进程、线程和协程
    Drools 入门案例——手把手教你
    如何安装Virtual Box的VBox Guest Additions扩展程序
    betterZip解压后压缩包会删除 zip文件解压后原压缩文件能不能删掉
    undefined method `license' when mac brew install
  • 原文地址:https://www.cnblogs.com/tanghuimin0713/p/3987527.html
Copyright © 2020-2023  润新知