zoukankan      html  css  js  c++  java
  • 2016.9.22感想及收获

    面试篇

    今天参加了科陆的面试,做了一下面试题,C语言部分几乎没有什么问题,但是软件类的题目不仅涉及到C语言、还有Java和C#,也还考到了数据库的知识。

    值得注意的面试题有:

    1、让程序在绝对地址0x100处执行。

    我写的答案是:(void(*0x100)(void))();

    结果在VS下编译通不过,网上有人说这样写:(void(*)(void)(0x100))();或者*(void(*)(void)(0x100))();编译同样通不过。

    于是尝试在linux下编译以上两端相同的代码:其中按第一种写法,系统提示语法错误,同windows下一样。然而第二种写法,linux下系统提示说:called object is not a function or function pointer...

    从上述错误可以看出,在linux下面,后者的语法应该是没有错的,只不过系统认为0x100不是一个函数或者函数指针。

    最后我在ARM开发环境KEIL上编译上述代码,同样编译不过。所以说,网上说的正确答案(void(*)(void)(0x100))();或者*(void(*)(void)(0x100))();也是不符合实际情况的。当然考试时还是写这个答案吧,毕竟考官不见得亲自去编写过这条代码。

    2、请问运行Test函数会有什么样的结果?

    void GetMemory(char *p)
    {
      p = (char*)malloc(100);
    }
    
    void Test(void)
    {
      char *str = NULL;
      GetMemory(str);
      strcpy(str,"hello world");
      printf(str);
    }
    

    看第一眼觉得这段代码没什么问题,后来仔细看也没发现什么问题。于是在linux下用gcc将上述代码编译了一下,编译通过。但是运行时系统提示:段错误。

    于是再次仔细查看上述代码,发现了一个低级问题,出题者耍的小伎俩:

    从函数GetMemory的定义看来,该函数的传值方式是址传递,即传递进函数的是变量地址。但是仔细一看,函数里面用的也是变量的地址,而不是变量本身,所以这里实质上还是一个值传递方式,而非址传递。所以在Test函数中执行GetMemory(str);之后,str的值不变还是NULL。所以导致后面出错。

    发现了问题,于是乎我将代码修改了一下:

    void GetMemory(char **p)
    {
      *p = (char*)malloc(100);
    }
    
    void Test(void)
    {
      char *str = NULL;
      GetMemory(&str);
      strcpy(str,"hello world");
      printf(str);
    }
    

    在linux编译成功,运行结果为hello world

    这个时候看第三题,居然是:请问运行Test2函数会有什么效果?出题者只不过将我上述修改的代码中Test换成了Test2而已。所以第三题运行结果应该是Hello world

    3、在一个32位系统中,数据结构定义如下,请问sizeof(S2)=?

    #pragma pack(4)
    struct s1
    {
      short a;
      long b;
    }
    
    struct s2
    {
      char c;
      s1 d;
      long long e;
    }
    

    这一题再次考察结构体里面的字节对齐和结构体大小计算,先回顾以下知识点:

    a、32位机各个数据类型长度为:

    char               8b               1Byte

    short            16b              2Byte

    int                32b              4Byte

    float             32b              4Byte

    long             32b              4Byte

    long long      64b              8Byte

    double         64b              8Byte

    long double  96b             12Byte

    b、关于之前说的结构体对齐规则:

     i、结构体的第一个成员的地址偏移量(offset)为0;

     ii、在没有用#pragma pack(n)指令指定对齐参数n时,对齐参数n=结构体中占用内存最大的那个成员变量所占内存的大小m;在用#pragma pack(n)指令指定对齐参数n后,系统将min(n,m)作为对齐参数。

     iii、每个成员变量都要对齐,如果对齐参数为n,该成员变量所占字节数为p,则该成员变量的偏移地址%min(n,p)=0。也就是最小化长度规则。

     iv、结构体总大小: 对齐后的长度必须是对齐参数n的整数倍。

     v、补充:如果结构体A中还有结构体B,那么B的对齐方式是选它里面最长的成员的对齐方式 
    所以计算结构体大小要走三步,首先确定是当前程序按照几对齐,接着计算每个结构体变量的大小和偏移,最后计算结构体总大小。

    c、综合归纳一下:

    i、32位机下,要注意以下数据类型的长度:short 一般是16b,不得比int长。int和float很显然是32b,但是double有64b而long仍然只有32b,只有“双龙(long)合璧”即long long 才是64位。最后最长的一个是long double 占12个字节共96位。

    ii、结构体的对齐把握两点:对齐参数和偏移地址

    对齐参数的计算很简单,参看b.ii。

    计算每个成员的偏移地址参看b.iii。

    通过以上回顾,得出题目答案为sizeof(S1) = 8,sizeof(S2)=24;

    在linux下验证得:8和20;

  • 相关阅读:
    Oracle列转行函数使用
    JavaScript笔记整理
    23种设计模式之桥梁模式
    23种设计模式之状态模式
    23种设计模式之解释器模式
    23种设计模式之备忘录模式
    23种设计模式之访问者模式
    23种设计模式之观察者模式
    23种设计模式之组合模式
    23种设计模式之适配器模式
  • 原文地址:https://www.cnblogs.com/wan0807/p/5898145.html
Copyright © 2011-2022 走看看