一:相关语言部分
1.写出运行结果:
{// test2
union V {
struct X {
unsigned char s1:2;
unsigned char s2:3;
unsigned char s3:3;
} x;
unsigned char c;
}v;
v.c = 100;
printf("%d", v.x.s3);
}
第一个成员定义应该在低位置。
3
------------------------------------------------------------------------------
2:用C++写个程序,如何判断一个操作系统是16位还是32位的?不能用sizeof()函数
A1:
16位的系统下,
int i = 65536;
cout << i; // 输出0;
int i = 65535;
cout << i; // 输出-1;
32位的系统下,
int i = 65536;
cout << i; // 输出65536;
int i = 65535;
cout << i; // 输出65535;
A2:
int a = ~0;
if( a>65536 )
{
cout<<"32 bit"<<endl;
}
else
{
cout<<"16 bit"<<endl;
}
------------------------------------------------------------------------------
3:试编写函数判断计算机的字节存储顺序是开序(little endian)
还是降序(bigendian)
解释:
对于字节,按通常顺序依次在内存中存放。
对于字或双字,在该字(或双字)的内部,则按“倒字存放” 原则存储(little_endian),
具体如下:
对一个字,存储时先存放低字节,再存放高字节(即低字节占低地址,
高字节占高地址)。字的地址是指其低字节的地址。
对一个双字,存储时先存放低字,再存放高字(即低字占低地址,高
字占高地址)。双字的地址是指其低字的地址。在每个字的内部,
同样按低字原则存放。
注意,无论是字节、字、双字,总体是还是往上长的,所谓倒是指在每个
字(或双字)的内部是倒的,但字与字(或双字与双字)之间还是
顺序存放的。
A1:
bool IsBigendian()
{
unsigned short usData = 0x1122;
unsigned char *pucData = (unsigned char*)&usData;
return (*pucData == 0x22);
}
A2:
int checkCPU()
{
UNION f
{
int a;
char b;
}c;
c.a = 1;
return (c.b == 1);
}
二:内存使用
关键字volatile有什么含意?并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这
样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在
用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使
用保存在寄存器里的备份。下面是volatile变量的几个例子:
-> 并行设备的硬件寄存器(如:状态寄存器)
-> 一个中断服务子程序中会访问到的非自动变量(Non-automatic
variables)
-> 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员
和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、
中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得
volatile的内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),
我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重
要性。
-> 一个参数既可以是const还可以是volatile吗?解释为什么。
-> 一个指针可以是volatile 吗?解释为什么。
-> 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
-> 是的。一个例子是只读的状态寄存器。它是volatile因为它可能
被意想不到地改变。它是const 因为程序不应该试图去修改它。
-> 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该
一个指向一个buffer的指针时。
-> 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的
平方,但是,由于*ptr指向一个volatile型参数,编译器将产生
类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。
结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
三:中断相关
中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供
一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字
__interrupt。下面的代码就使用了__interrupt关键字去定义了一个
中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:
1: ISR 不能返回一个值。如果你不懂这个,那么你不会被雇
用的。
2: ISR 不能传递参数。如果你没有看到这一点,你被雇用的
机会等同第一项。
3: 在许多的处理器/编译器中,浮点一般都是不可重入的。有
些处理器/编译器需要让额处的寄存器入栈,有些处理器/编
译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而
有效率的,在ISR中做浮点运算是不明智的。
4:与第三点一脉相承,printf()经常有重入和性能上的问题。
如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果
你能得到后两点,那么你的被雇用前景越来越光明了。
四:函数调用;
1:已知,一个函数的地址为0Xa8,定义方式为无参数,如何调用它??