嵌入式C语言面试题(二)
1.评价下面的代码
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
unsigned int zero = 0; //OK
unsigned int compzero = 0xFFFF;//unsigned int 在16位OS中可以这样表示,在32位OS中表示错误.
应该是:
unsigned int compzero = ~0;
2.求c=a+++b;
int a = 5, b = 7, c;
c = a+++b;
c = a+++b = 12;
c = a+++b被编译器理解为a+++b
3.求值
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
则语句 printf("%d",sizeof(struct data)+sizeof(max));的执行结果是?
sizeof(struct date) 分析如下:DATE是一个union,long i可能是4 byte,也可能是8 byte,int k[5]=20 byte,char c1个字节,因此,如果long i是4 byte,则sizeof(DATE)=20.此时struct data的大小为:cat(4byte),cow(20byte),dog(8 byte)合计32个字节.So,总长度为52个字节;
如果long i是8个字节,则DATE是24个字节,则4,24,8=36,合计60个字节.
4.下出下面的输出
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;//str1!=str2,因为是两个不同的数组
cout << ( str3 == str4 ) << endl;//str3!=str4,因为i是两个不同的常量数组
cout << ( str5 == str6 ) << endl;//一样,同样的指针
cout << ( str7 == str8 ) << endl;//一样,同样的指针
5.写出输出结果
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
*(a+1)=a[1],因此,第一个输出是int数据2.
ptr = (int*)(&a+1);首先,a是数组的首地址,那么&a+1到底是表示a的地址加1还是其他意思?
我们必须记住一点:指针加减的数字是以指针指向的数据类型为量度的,由于&a是指向a[5]这个整型数组首地址的地址,也就说&a的数据类型为数组指针(int (*)[5]).这个数组指针指向的数据类型是int a[5],长度为20个字节.因此,&a+1(ptr)表示数组首地址+20,int *ptr =&a+1. 因此,ptr-1其实就是指向数组a的第5个元素,也就是5.
6.请问以下代码有什么问题
int main()
{
char a='a';
char *str=&a;//str的地址空间只有1个字符
strcpy(str,"hello");//指针越界,segment fault.
printf(str);
char* s="AAA";//字符串数组
printf("%s",s);//.
s[0]='B';//字符串常量,不能修改.
printf("%s",s);//.
return 0;
}
7.请问下列表达式哪些会被编译器禁止?为什么?
int a=248; //OK
b=4;//b没有定义类型,error!
int const c=21;//int常量OK
const int *d=&a;//常量指针,指针指向的数值不能修改,这里做初始化,OK
int *const e=&b;//指针常量,其值为指向b的地址,OK.后面不能修改此指针值.
int const *f =&a;//常量指针,指针指向的值不能修改,这里做初始化,OK
*c=32;//c不是指针,不能有取值运算.error!
d=&b;//常量指针,指针的值可以修改,但原来的地址对应的数值不会修改.OK
*d=43;//常量指针,指针指向的值不能修改,error!
e=34;//指针不能直接赋值,error!
e=&a;//指针常量,指针的值不能修改.error!
f=0x321f;//常量指针,指针指向的值不能修改,但建议指针不要直接赋值
8.交换两个变量的值,不使用第三个变量
1.a = a^b;
a = a^b;
b = a^b;
2.a = a+b
b = a-b
a = a-b
9.下面的程序会出现什么结果?
#include <stdio.h>
#include <stdlib.h>
void getmemory(char *p) //
{
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( )
{
char *str=NULL;
getmemory(str);
//str=NULL,在getmemory函数里面,char*p ,p(指针值)作了修改,但是str(实参)没有修改,因此,调用后,str还是=NULL
printf("%s/n",str);
free(str);
return 0;
}
10.分析以下代码的输出是什么?
int _tmain(int argc, _TCHAR* argv[])
{
unsigned short A=10;
printf("~A=%u\n",~A);
printf("~A=%d\n",~A);
printf("~A=%x\n",~A);
char c=128;
printf("c=%d\n",c);
return 0;
}
第一个,将A作为%u,无符号整数,A=0x0A,则~A = 0xFF FF FF F5 ,则其值为2的32次方-11.
第二个,将A作为有符号整数,~A=0xFF FF FF F5,为负数,由于负数在计算机中用补码表示,其补码为0x0B=-11.
第三个,将A作为16进制数,~A = 0xFF FF FF F5, 故其值就是0xFFFFFFF5.
第四个,c=128=0b 1000 0000,如果解析为有符号整数,则输出为负数,其补码=-128.so 输出为-128.
11.绝对地址0x100000赋值且想让程序跳转到绝对地址是0x100000去执行,如何写代码?
void (* p)() =(unsigned int*)0x100000;
//一个函数指针,返回值为空,参数为空.
p();
12.求下面结构的sizeof(A)大小.
struct A
{
char t::4;
char k:4;
unsigned short i:8;
unsigned long m;
};
分析:假定编译器设置的对齐参数为#pragma pack(4);(4字节对齐),则:
若为32位OS,
t,k共占据1个字节,unsigned short 2 byte,unsigned long m 4 byte,则对齐单位为4 byte,故t和k占据1个字节,i偏移量从2开始,占据2个字节,m偏移量从4开始,占据4个字节,合计8个字节.
若为64位OS,
t,k共占据1个字节,unsigned short 2 byte, unsigned long m 8个字节,则对齐单位为4 byte,故t和k占据1个字节,i偏移量从2开始,长度为2,m偏移量从4开始,长度为8,共计12个字节.
13.给出下面程序的答案.
typedef struct AA
{
int b1:5;
int b2:2;
}AA;
void main()
{
AA aa;
char cc[100];
strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");//strcpy在最后补0了.
memcpy(&aa,cc,sizeof(AA));
cout << aa.b1 <<endl;
cout << aa.b2 <<endl;
}
//sizeof(AA)=4;拷贝4个字符“0123”其16进制内容为0x30,0x31,0x32,0x33即:00110000 00110001 00110010 00110011.
//b1和b2占据了这四个字节的前面字节的7位,即b1:0b10000,b2=0b01;int是有符号整数,b1=-16,b2=1
14.给出下面程序的输出.
struct bit
{
int a:3;
int b:2;
int c:3;
};
int main()
{
bit s;
char *c=(char*)&s;
cout<<sizeof(bit)<<endl;//sizeof(bit)=4
*c=0x99;
cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
int a=-1;
printf("%x",a);
return 0;
}
分析:
sizeof(struct bit)=4.
*c = 0x99= 0b1001 1001,a是前3位,故a是001,b是11,c是100,由于均为int型,故s.a=1,s.b=-1,s.c=-4
a=-1, 1的原码是-0x00000001,-1的补码是0xFFFFFFFF.故a打印出来0xFFFFFFFF.
15.求以下几个结构的长度
struct name1{
char str; //1个字节;
short x;//2个字节;
int num;//4个字节
}
struct name2{
char str;//1个字节
int num;//4个字节;
short x;//2个字节
}
假设编译器对齐参数设置为# pragma pack(4),则:
struct name1:
此结构中长度最大的值为num(4),两者之间的较小值为4,第一个char str从0开始,第二个short的偏移量为其长度与4的较小值,故为2,第三个int num 长度为4,故其偏移量为4,因此,合计长度为8.
struct name2:
首先,其单位对齐长度为num的长度与pack(4)两者的最小值(4).
char str 1个字节,占据1个字节,num 占据4个字节,偏移量为4的倍数,故从4开始,占据4-7四个 byte,short x是两个字节,故偏移量为2的倍数,偏移量为8,占据2个字节,但总长度应该是4的整数倍,故最终的占据长度为4+4+4=12.
从上面可以看出,为了节约空间,数据类型占据字节长的结构成员,应该放在结构的后面.
struct s1
{
int i: 8;//8位bit
int j: 4;//4位bit
int a: 3;//3位bit
double b;
};
struct s2
{
int i: 8;//
int j: 4;//两个int,共需要2个字节,//
double b;//第三个,需要8,其偏移量从8开始,长度为8.
int a:3;//第四个,偏移量从16开始,长度为4.因此,且总长度需要8的倍数,因此,此结构的总长度为8+8+8=24.
};
假设为#pragma pack(4),则:
struct s1:
i,j,a均为int型,合计占据15个字节,由于单位对齐长度为4,故这三个bit位共占据2个字节,double b始终占据8 byte,则其偏移量为4的倍数,本身占据8个字节,故struct s1的长度为12.
struct s2:
i,j,为int型,共占据2个字节;double b占据8个字节,故为4-11 8个字节,int a:3占据4个字节,故合计为4+8+4=16个字节.(关于结构体长度的判断,请参见笔者在csdn的相关其他文章)
16.填空
struct BBB
{
long num;//4个字节 offset 0+4
char *name;//4个字节 offset 4+4
short int data;//2个字节 offset 8+2
char ha;//1个字节 offset 10+2
short ba[5];
}*p;
p=0x1000000;
p+0x200=____;
(unsigned long*)p+0x200=____;
(char*)p+0x200=____;
分析如下:
struct BBB
{
//单位对齐长度为4.
long num;//4个字节 0+4(offset+占据字节,下同)
char *name;//4个字节 4+4
short int data;//2个字节 8+2
char ha;//1个字节 10+2
short ba[5]; 12+10(12)
}*p;
p=0x1000000;
p+0x200=____;
(unsigned long*)p+0x200=____;
(char*)p+0x200=____;
由于long在32位OS和64位OS下面有不同的长度,故分开讨论:
假设为32位OS:根据笔者C语言结构体所占空间分析(https://blog.csdn.net/cdma_zte_c/article/details/119943850)可知,struct BBB占据22个字节,但应该为4的倍数,故占据空间为24 Byte.
所以p+0x200 = p+0x20024 = p + 0x2000x18
(unsigned long*)p+0x200= p + 0x200sizeof(unsigned long)=p+ 0x200 * 4
(char)p + 0x200 = p + 0x200*sizeof(char)=p+0x200
假设为64位OS,则分析如下:
struct BBB
{
//单位对齐长度为4
long num;//8个字节 0+8(offset+占据字节,下同)
char *name;//8个字节 8+8
short int data;//2个字节 16+2
char ha;//1个字节 18+2
short ba[5]; 20+10(12)
}*p;
故合计占据长度为32 byte.
则后面就好计算了.
17.写出程序输出结果
void g(int**);
int main()
{
int line[10],i;
int *p=line; //p是一个指向int数据的指针,然后赋值给它line,
//这样,p就指向了line的首地址.指针p的类型是 (int *)[10];
for (i=0;i<10;i++)
{
*p=i;// *p = i,将i赋值给line的第i个元素。
g(&p);//因为p是一个指针,把指针地址当作参数传递到函数.
}
for(i=0;i<10;i++)
printf("%d\n",line[i]);
return 0;
}
void g(int**p)
{
(**p)++;//根据上面的分析,(**p)就是line数组当前位值的数值,后++,由于(**p)++操作的是实际的内存中的数值,故调用g函数的line数组中的值会相应修改.
(*p)++;//*p是指针,指向line数组的相应位置,现在(*p)++,相当于指向line数组相关元素位置的指针的值++(指针的值是保存在指针p对应的内存中,指针的值++,就是p指向的内存中的值++),因此,就是line数组的当前元素位置后移.然后再次赋值,再次+1.故输出是1,2,3,4,5,6,7,8,9,10
}
分析情况参见源码部分.
18.写出程序输出结果
int arr[] = {6,7,8,9,10};
int *ptr = arr;//ptr指向数组头部
*(ptr++)+=123; // 首先*ptr = 123,然后ptr++.
printf(“ %d %d ”, *ptr, *(++ptr));//首先计算右边的*(++ptr),ptr+2 ,指向数据8,*ptr=8.故两者输出都是8.
typedef struct
{
int a:2;
int b:2;
int c:1;
}test;
test t;
t.a = 1;//a=0x01,正数,因此,打印为1.
t.b = 3;//a=0x11,负数,求补码,因此,打印为-1
t.c = 1;//c=0x1,负数,求补码,打印为-1
printf("%d",t.a);
printf("%d",t.b);
printf("%d",t.c);
解答参见原文代码.