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;

posted @ 2016-09-22 22:06  玩呀熊熊  阅读(190)  评论(0编辑  收藏  举报