面试篇
今天参加了科陆的面试,做了一下面试题,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;