2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > linux c程序面试题 嵌入式linux面试题解析(二)——C语言部分一

linux c程序面试题 嵌入式linux面试题解析(二)——C语言部分一

时间:2023-12-21 16:39:14

相关推荐

linux c程序面试题 嵌入式linux面试题解析(二)——C语言部分一

嵌入式linux开发面试题解析(二)——C语言部分一

1、编写统计一个数二进制表示中有多少个1的函数

int count_bit1(int m)

{

int count = 0;

while(m)

{

m = m & (m-1);

count++;

}

return count;

}

2、编写一个函数判断一个数是否是2的N次方

int is_number(int num)

{

if( m & (m - 1) == 0)

return 0;//如果一个数是2的N次方,返回0

else

return 1;//如果一个数不是2的N次方,返回1

}

3、用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#defineSECONDS_PER_YEAR(1UL*60 * 60 * 24 * 365)

兼容16位CPU,#defineSECONDS_PER_YEAR(60 * 60 * 24 * 365)UL这种用法在GCC是不能编译通过的。

4、预处理器标识#error的目的是什么?

#errorerror-message停止编译并显示错误信息,error-message不需要双引号

5、嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?

while(1){

;}

6、用变量a给出下面的定义

a)一个整型数(An integer)b)一个指向整型数的指针(A pointer to an integer)c)一个指向指针的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)d)一个有10个整型数的数组(An array of 10 integers)

e)一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)f)一个指向有10个整型数数组的指针(A pointer to an array of 10 integers)g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as anargument and returns an integer)h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(An array of ten pointers to functions that take aninteger argument and return an integer)

定义如下:

a) int a; // An integerb) int *a; // A pointer to an integerc) int **a; // A pointer to a pointer to an integerd) int a[10]; // An array of 10 integers

e)int *a[10]; // Anarray of 10 pointers to integers等价于int *(a[10]);

f)int (*a)[10];// Apointer to an array of 10 integersg)int (*max_function)(int a); // A pointer to afunction a that takes an integer argument and returns an integer

h)int (*a[10])(int);// An array of 10 pointers to functions that take an integer argument andreturn an integer

7、键字static的作用是什么?

在C语言中,关键字static有三个明显的作用:A、一旦声明为静态变量,在编译时刻开始永远存在,不受作用域范围约束,但是如果是局部静态变量,则此静态变量只能在局部作用域内使用,超出范围不能使用,但是它确实还占用内存,还存在.B、在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。C、在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

8、typedef与define的区别

typedef是C语言中用来声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

#define是预处理指令,是宏定义。

int a = 80;

typedef int * PINT;

const PINT p = &a;//const修饰指针类型,限定指针变量p为只读

PINT const p = &a;//const修饰指针类型,限定指针变量p为只读

9、k输出的值是多少

int main(int argc, char *argv[])

{

char k = 0;

int i;

for(i = 0; i < 127; i++)

k += i & 3;

printf("k = %d\n", k);

return 0;

}

i:01234567

i & 3:01230123

k:01236679

i共计有32组0123和一组01组成

因此k=32 *(0 + 1 + 2 + 3)+(0 + 1)= 187

由于k为char,所以k在127以后的数是-127,-126....,所以

K = (187-127)+ (-127)= -67;

输出-67;

10、嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。

在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为

0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。

解答出如下:

int*ptr;

ptr=(int*)0x67a9;

*ptr=0xaa55;

嵌入式开发中常用应用:

#define rPCONA(*(volatile unsigned *)0x1D20000)

#define rPDATA(*(volatile unsigned *)0x1D20004)

11、下列代码输出结果是多少

charstr1[]="abc";

charstr2[]="abc";

constcharstr3[]="abc";

constcharstr4[]="abc";

constchar*str5="abc";

constchar*str6="abc";

char*str7="abc";

char*str8="abc";

cout<

cout<

cout<

cout<

解答:

输出结果是:0011

解析:str1,str2,str3,str4是数组变量,有各自的内存空间;而str5,str6,str7,str8是指针,指向相同的常量区域。

12、简介##和#的作用

预处理器运算符##是连接符号,由两个井号组成,其功能是在带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串。但它不可以是第一个或者最后一个子串。所谓的子串(token)就是指编译器能够识别的最小语法单元。如果替换文本中的参数与##相邻,则该参数将被实际参数替换,##与前后的空白将被删除,并对替换后的结果重新扫描。形成一个新的标号,如果这样产生的记号无效,或者结果依赖于##运算顺序,则结果没有定义。

#definepaste(front,back)front##back

宏调用paste(name,_xiaobai)的结果为name_xiaobai

#符是把传递过来的参数当成字符串进行替代

#definedprint(expr)printf(#expr"=%d\n",expr)

inta=20,b=10;

dprint(a/b);

打印出:a/b=2

13、关键字volatile有什么含意?并给出三个不同的例子。

定义为volatile的变量表明变量可能会被意想不到地改变,编译器就不会去假设这个变量的值。准确地说,优化器在用到volatile修饰的变量时必须每次都小心地重新读取变量的值,而不是使用保存在寄存器里的备份。

使用volatile变量的例子:A、并行设备的硬件寄存器(如:状态寄存器)

B、一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)C、多线程应用中被几个任务共享的变量

深入理解:

(1)一个参数既可以是const还可以是volatile吗?解释为什么。

是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。(2)一个指针可以是volatile吗?解释为什么。

是的。尽管这并不很常见。一个例子是当一个中服务子程序修改一个指向一个buffer的指针时。(3)下面的函数有什么错误:intsquare(volatileint*ptr){return*ptr**ptr;}

函数目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:intsquare(volatileint*ptr){inta,b;a=*ptr;b=*ptr;returna*b;}

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,函数可能返回不是你所期望的平方值。

longsquare(volatileint*ptr){inta;a=*ptr;returna*a;}

14、嵌入式系统中断服务子程序(ISR)

中断是嵌入式系统中重要的组成部分,导致了很多编译开发商提供一种扩展—让标准C支持中断。具体代表是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。

__interrupt double compute_area (double radius)

{

double area = PI * radius * radius;

printf("Area = %f", area);

return area;

}

中断程序的特点:

A、ISR 不能返回一个值。

B、ISR 不能传递参数。

C、在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。

D、printf()经常有重入和性能上的问题。

15、嵌入式C语言开发中的位操作

A、将寄存器指定位(第n位)置为1

GPXX|= (1<

GPXX |=(1<< 7) | (1<< 4 ) | (1<< 0);//第0、4、7位置1,其他保留

B、将寄存器指定位(第n位)置为0

GPXX&= ~(1<

将寄存器的第n位清0,而又不影响其它位的现有状态。

GPXX&= ~(1<<4)

C、嵌入式开发位操作实例

unsigned int i = 0x00ff1234;

//i |= (0x1<<13);//bit13置1

//i |= (0xF<<4);//bit4-bit7置1

//i &= ~(1<<17);//清除bit17

//i &= ~(0x1f<<12);//清除bit12开始的5位

//取出bit3-bit8

//i &= (0x3F<<3);//保留bit3-bit8,其他位清零

//i >>= 3;//右移3位

//给寄存器的bit7-bit17赋值937

//i &= ~(0x7FF<<7);//bit7-bit17清零

//i |= (937<<7);//bit7-bit17赋值

//将寄存器bit7-bit17的值加17

//unsigned int a = i;//将a作为i的副本,避免i的其他位被修改

//a &= (0x7FF<<7);//取出bit7-bit17

//a >>= 7;//

//a += 17;//加17

//i &= ~(0x7FF<<7);//将i的bit7-bit17清零

//i |= (a<<7);//将+17后的数写入bit7-bit17,其他位不变

//给一个寄存器的bit7-bit17赋值937,同时给bit21-bit25赋值17

i &= ~((0x7FF<<7)| (0x1F<<21));//bit7-bit17、bit21-bit25清零

i |=((937<<7)| (17<<21));//bit7-bit17、bit21-bit25赋值

D、位操作的宏定义

//用宏定义将32位数x的第n位(bit0为第1位)置位

#define SET_BIT_N(x,n) (x | (1U<

//用宏定义将32位数x的第n位(bit0为第1位)清零

#define CLEAR_BIT_N(x,n) (x & (~(1U<

//用宏定义将32位数x的第n位到第m位(bit0为第1位)置位

#define SET_BITS_N_M(x,n,m) (x | (((~0U)>>(32-(m-n+1)))<

//用宏定义将32位数x的第n位到第m位(bit0为第1位)清零

#define CLEAR_BITS_N_M(x,n,m) (x & (~(((~0U)>>(32-(m-n+1)))<

//用宏定义获取32位数x的第n位到第m位(bit0为第1位)的部分

#define GET_BITS_N_M(x,n,m) ((x & ~(~(0U)<>(n-1))

16、大小端的介绍

Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。数字0x12 34 56 78在内存中的表示形式为:

大端模式:

低地址 -----------------> 高地址0x12 | 0x34 | 0x56 | 0x78

小端模式:

低地址 ------------------> 高地址0x78 | 0x56 | 0x34 | 0x12

Big-Endian: 低地址存放高位,如下:高地址---------------buf[3] (0x78) -- 低位buf[2] (0x56)buf[1] (0x34)buf[0] (0x12) -- 高位---------------低地址Little-Endian: 低地址存放低位,如下:高地址---------------buf[3] (0x12) -- 高位buf[2] (0x34)buf[1] (0x56)buf[0] (0x78) -- 低位--------------低地址

C语言实现测试大小端:

#include

int main(int argc, char **argv)

{

union

{

int a;

char b;

}c;

c.a = 1;

if(c.b == 1)

{

printf("little\n");

}

else

printf("big\n");

return 0;

}

常见CPU的大小端:

Big Endian : PowerPC、IBM、SunLittle Endian : x86、DEC

常见文件的字节序:

Adobe PS – Big EndianBMP – Little EndianDXF(AutoCAD) – VariableGIF – Little EndianJPEG – Big EndianMacPaint – Big EndianRTF – Little Endian

Java和所有的网络通讯协议都是使用Big-Endian的编码。

大小端的转换:

16位

#defineBigtoLittle16(A)((((uint16)(A)&0xff00)>>8)|\

(((uint16)(A)&0x00ff)<

32位

#defineBigtoLittle32(A)((((uint32)(A)&0xff000000)>>24)|\

(((uint32)(A)&0x00ff0000)>>8)|\

(((uint32)(A)&0x0000ff00)<

(((uint32)(A)&0x000000ff)<

从软件的角度上,不同端模式的处理器进行数据传递时必须要考虑端模式的不同。如进行网络数据传递时,必须要考虑端模式的转换。在Socket接口编程中,以下几个函数用于大小端字节序的转换。

ntohs(n)//16位数据类型网络字节顺序到主机字节顺序的转换

htons(n)//16位数据类型主机字节顺序到网络字节顺序的转换

ntohl(n)//32位数据类型网络字节顺序到主机字节顺序的转换

htonl(n)//32位数据类型主机字节顺序到网络字节顺序的转换

17、引用和指针有什么区别?

A、应用必须初始化,指针不必;

B、引用处画化后不能改变,指针可以被改变;

C、不存在指向空值的引用,但存在指向空值的指针;

18、写出float,bool,int类型与零的比较,假设变量为X:

Int:if(x==0)

Float:if(x>-0.0000001&&x<0.0000001)

Bool: if(x==false)

19、多维数组的定义

在数组定义int a[2][2]={{3},{2,3}};则a[0][1]的值为0。(对)

#include

intmain(int argc,char * argv[])

{

int a [3][2]={(0,1),(2,3),(4,5)};

int *p;

p=a [0];

printf("%d",p[0]);

}

问打印出来结果是多少?

答案:1

分析:花括号里嵌套的是小括号而不是花括号!这里是花括号里面嵌套了逗号表达式!其实这个赋值就相当于int a [3][2]={ 1, 3, 5};

20、评价下面的代码片断

unsigned int zero = 0;unsigned int compzero = 0xFFFF;

对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:

unsigned int compzero = ~0;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。