欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux 笔试题

程序员文章站 2022-03-03 11:44:30
...

  Linux应用程序员:做一、二题 ,考试时间:1.5小时

Linux驱动程序员:做一、二(可选做)、三题,考试时间:2小时

一、            C/C++语言

1.        头文件中的ifndef/define/endif 干什么用?

答:防止该头文件被重复引用

 

2.        数据类型判断

typedefint (*test) ( float * , float*)
test tmp;

tmp 的类型是:___C___。

(a) 函数的指针,该函数以 两个指向浮点数(float)的指针(pointer)作为参数(arguments),并且函数的返回值类型是整型指针

(b) 整型指针

(c) 函数的指针,该函数以两个指向浮点数(float)的指针(pointer)作为参数(arguments),并且函数的返回值类型是整型

(d) 以上都不是

 

3.        C++的类和C里面的struct有什么区别?

struct中的成员默认是public的,class中的默认是private

class有默认的构造、析构函数,struct没有

class中可以有虚函数,struct不行

class可以被继承,struct

4.        阅读并作答

下面的代码输出是什么,为什么?

void test(void)
{
    unsigned int a = 6;
    int b = -20;
    (a+b > 6) ? puts("> 6") : puts("<=6");
}

答:”>6”,因为有符号和无符号混合运算时,有符号数自动转换为无符号数值进行运算

 

5.        阅读并作答

int counter (int i)

{

static int count =0;

count = count +i;

return (count );

}

main()

{

int i , j;

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

j = counter(i);

}

本程序执行到最后,j的值是:__B___。

(a) 10

(b) 15

(c) 6

(d) 7

 

6.        阅读并作答

main()
{
int a[][3] = { 1,2,3 ,4,5,6};
int (*ptr)[3] =a;
printf("%d %d " ,(*ptr)[1], (*ptr)[2] );
++ptr;
printf("%d %d" ,(*ptr)[1], (*ptr)[2] );
}

这段程序的输出是: __A___。

(a) 2 3 5 6
(b) 2 3 4 5
(c) 4 5 0 0
(d) 以上均不对

7.        .以下表达式符合规范的是___D__。
a. while (p && *p)      // p为指针变量
b. if (1 == flag)      // flag为布尔变量
c. if (0.0 == x)       // x为浮点变量
d. if (strlen(strName) != 0)  // strName为字符串变量

8.        给定一个4字节整型变量a,以bit0~bit31标识二进制位,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。#define BIT3 (1<<3)

a |= BIT3;

a ^= ~BIT3;

9.        编码实现以下几个小功能

  (1) 编写两个宏实现一个字节无符号整数的16进制与压缩bcd码进行互相转换。假设数值大小不超过99

例如:“0x12”是16进制表示法,10进制数为“18”,记为“0x18”

#define BYT_HEX2BCD(x)  ( (x/10 )<<4) + (x%10) 

#define BYT_BCD2HEX(x)  ( (x>>4)*10 ) + (x&0x0f)

 

  (2) 写个函数实现将ASCII码串转换为16进制数组

     例:ASCII串为“8e349bcd45”转换为

         0x8e,0x34,0x9b,0xcd,0x45

intStrAsc2Hex(unsigned char *dst,const char * src, int len)

{

    int i;

    unsigned char dtemp,stemp;

    char *ptr;

    ptr=const_cast<char *>(src);

    if(len%2) return 0;

    len/=2;

    for(i=0;i<len;i++)    {

       if( (*ptr) >='0' &&(*ptr)<='9' )stemp=*ptr-'0';

       if( (*ptr) >='A' &&(*ptr)<='F' )stemp=*ptr-'A'+0x0a;

       if( (*ptr) >='a' &&(*ptr)<='f' )stemp=*ptr-'a'+0X0a;

       dtemp=stemp<<4;

       ptr++;

       if( (*ptr) >='0' &&(*ptr)<='9' )stemp=*ptr-'0';

       if( (*ptr) >='A' &&(*ptr)<='F' )stemp=*ptr-'A'+0x0a;

       if( (*ptr) >='a' &&(*ptr)<='f' )stemp=*ptr-'a'+0X0a;

       *dst++=dtemp|stemp;

       ptr++;   

    }

    return len;

}

10.     阅读并作答

阅读题。

(1)voidGetMemory(char *p)

{

p = (char *)malloc(100);

}

voidTest(void)

{

char *str = NULL;

GetMemory(str);

strcpy(str, "helloworld");

printf(str);

}

请问运行Test函数会有什么样的结果?为什么?

程序出错。

因为GetMemory并不能传递动态内存,

Test函数中的 str一直都是 NULL

strcpy(str,"hello world");将使程序出错。

同时GetMemory中分配的内存得不到释放,内存泄漏

(2)char*GetMemory(void)

{    

char p[] = "helloworld";

return p;

}

voidTest(void)

{

char *str = NULL;

str = GetMemory();   

printf(str);

}

请问运行Test函数会有什么样的结果?为什么?

可能是乱码。

因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

(3)VoidGetMemory2(char **p, int num)

{

*p = (char *)malloc(num);

}

voidTest(void)

{

char *str = NULL;

GetMemory(&str, 100);

strcpy(str, "hello world");     

printf(str);     

}

请问运行Test函数会有什么样的结果?为什么?

能够输出hello,但内存泄漏

 

(4)       void Test(void)

{

char *str = (char *) malloc(100);

       strcpy(str, “hello”);

       free(str);     

       if(str != NULL)

       {

        strcpy(str, “world”);  

printf(str);

}

}

请问运行Test函数会有什么样的结果?为什么?

篡改动态内存区的内容,后果难以预料。因为free(str);之后,str成为野指针

 

11.     内存对齐

有如下定义:

#pragmapack(8)

structtagS1

{

       char c;

       int i;

};

#pragmapack()

 

#pragmapack(2)

structtagS2

{

       char c;

       int i;

};

#pragmapack()

 

若编译器支持指定的对齐方式,则计算:

sizeof(tagS1)= 8

sizeof(tagS2)= 6

12.     阅读并作答

指出下列代码运行时可能出错,或者编写不够规范的地方

int func(int par1, char par2)

{

int i;

i ++;

if( i == 1 ){

              ………………..

              par1= 100 / par1;

              ……………….

              char c = par2 ++;

              ………………

}

return par1;

}

1ij定义时没有初始化

2if() 中的 i ==1写法不规范,如果误写为i=1,编译仍通过,可逻辑不是预期的

3100 / par1时,没有对除数进行非0检查

4)函数的输入参数,最好写为v_iPar1v_cPar2,以表示是函数参数及各自的类型。(建议)

5if之后的大括号,最好单独一行。(建议)

13.     大端模式 / 小端/ 网络字节序

(1)       什么是大端模式,小端模式,网络字节序?

嵌入式系统开发者应该对Little-endianBig-endian模式非常了解。采用Littleendian模式的CPU对操作数的存放方式是从低字节到高字节,就是低地址放低字节,而Big-endian模式对操作数的存放方式是从高字节到低字节,就是低地址放高字节的拉。

(2)       请写一个函数,来判断处理器是大端还是小端模式

intCheckCpu()

{

    union test

    {

       int a;

       char b;

    }c;

    c.a = 1;

    return (1 == c.b)

}

大端则返回0,小端返回1

14.     链表

有如下链表结点定义:

structNode
{
int data ;
Node *next ;
};
typedef struct Node Node ;

已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)

二、            Linux应用开发

15.     Linux操作系统

(1)解释linux下常用命令:

rm  删除

cp  复制

mount  挂载

chmod  更改权限

ls 输出目录信息

(2)遇到不熟悉的命令,你会?

使用man命令查找帮助

 

16.       段错误调试

(1)      什么是段错误?

所谓的段错误就是指访问的内存超出了系统所给这个程序的内存空间,一旦程序发生了越界访问,CPU就会产生相应的异常保护,于是segmentationfault就出现了。

(2)      举例说明编程中通常碰到段错误的地方有哪些?

1

往受到系统保护的内存地址写数据(如内核占用的或者是其他程序正在使用的)

#include<stdio.h>

intmain()

{

   int i = 0;

   scanf ("%d", i);  /* should have used &i */

   printf ("%d\n", i);

   return 0;

    }

2

内存越界(数组越界,变量类型不一致等)

#include<stdio.h>

intmain()

{

   int b = 10;

   printf("%s\n", b);

   return 0;

}

(3)      如何发现程序中的段错误并处理掉?

(a)在程序内部的关键部位输出信息,可以跟踪段错误在代码中可能的位置。使用这种调试方法,可以用条件编译指令#ifdef DEBUG#endifprintf函数给包含起来,编译的时候加上-D DEBUG参数就可以查看调试信息。
(b)
gdb来调试,在编译的时候加上-g参数,用来显示调试信息,程序在运行到段错误的地方,会自动停下来并显示出错的行和行号
(c)
使用catchsegv命令来扑获段错误

 

17.   编写一个Makefile通用模板,要求可以实现以下功能:

make:编译和连接程序。
make objs:仅仅编译程序产生 .o 目标文件,不进行连接。
make clean:删除编译产生的目标文件和依赖文件。
make cleanall:删除目标文件、依赖文件以及可执行文件。
make rebuild:重新编译和连接程序

# The executable file name. 
# It must be specified. 
# PROGRAM   := a.out    # the executable name
PROGRAM   := 

# The directories in which source files reside.
# At least one path should be specified. 
# SRCDIRS   := .        # current directory
SRCDIRS   := 

# The source file types (headers excluded). 
# At least one type should be specified. 
# The valid suffixes are among of .c, .C, .cc, .cpp, .CPP, .c++, .cp, or .cxx.
# SRCEXTS   := .c      # C program
# SRCEXTS   := .cpp    # C++ program
# SRCEXTS   := .c .cpp # C/C++ program
SRCEXTS   := 

# The flags used by the cpp (man cpp for more).
# CPPFLAGS  := -Wall -Werror # show all warnings and take them as errors
CPPFLAGS  := 

# The compiling flags used only for C. 
# If it is a C++ program, no need to set these flags.
# If it is a C and C++ merging program, set these flags for the C parts.
CFLAGS    := 
CFLAGS    += 

# The compiling flags used only for C++. 
# If it is a C program, no need to set these flags.
# If it is a C and C++ merging program, set these flags for the C++ parts.
CXXFLAGS  := 
CXXFLAGS  += 

# The library and the link options ( C and C++ common).
LDFLAGS   := 
LDFLAGS   += 

## Implict Section: change the following only when necessary.
##===========================================================
# The C program compiler. Uncomment it to specify yours explicitly.
#CC      = gcc 

# The C++ program compiler. Uncomment it to specify yours explicitly.
#CXX     = g++ 

# Uncomment the 2 lines to compile C programs as C++ ones.
#CC      = $(CXX) 
#CFLAGS  = $(CXXFLAGS) 

# The command used to delete file. 
#RM        = rm -f

16. 你的项目中是否经常用到多进程和多线程编程?简要举例说明使用多进程和多线程的例子

 

 

三、            Linux驱动开发

1.        不需要编译内核的情况是(  D  )

A 删除系统不用的设备驱动程序时

B 升级内核时

C 添加新硬件时

D 将网卡激活

2.        关于i节点和超级块,下列论述不正确的是( B  )

A i节点是一个长度固定的表

B 超级块在文件系统的个数是唯一的

C i节点包含了描述一个文件所必需的全部信息

D 超级块记录了i节点表和空闲块表信息在磁盘中存放的位置

3.        USB

1)USB是一种常用的pc接口,他只有4根线,USB接口定义的4个信号分别是什么?

电源线、地线、USB信号正、USB信号负(差分)。

2)USB通过具有一定格式的“信包”(packet)按一定的“规程”(protocol)传输信息,并根据信息(内容)的性质分成4中传输类型:控制型、等时型、中断型、成块型,这四种传输类型中,哪些属于可靠传递,哪些不是可靠传递?

等时型不可靠

 

4.        数据复制

1)copy_to_user和put_user函数/宏的功能分别是什么,在linux编程中一般在什么情况下使用?

内核空间和用户空间之间的数据复制,前者针对一段内存地址,后者只能针对一个变量

2)请说明copy_to_user和__copy_to_user的区别。首部没有下划线的函数或宏要用额外的时间对所请求的线性地址区间进行有效性检查,而有下划线的则会跳过检查。当内核必须重复访问进程地址空间的同一块线性区时,比较高效的办法是开始时只对该地址检查一次,以后就不用再对该进程区进行检查了。

5.        1inux内核中jiffies变量记录的是什么数据,如何处理jiffies的溢出问题?

jiffies是自开机以来的时钟中断次数,是内核中的一个全局变量,是不停增长变化的,其在用户空间是不可直接使用的。同于任何c语言的int变量一样,jiffies在超过最大数值之后会溢出

Linux内核中提供了以下四个宏,可有效地解决由于jiffies溢出而造成程序逻辑出错的情况。

time_after(a,b)

time_before(a,b)

time_before_eq(a,b)

6.        驱动编程中有如下常用的结构:

static struct file_operations test_fops =

{

  .owner =THIS_MODULE,// 拥有该结构的模块的指针,一般为THIS_MODULE

  .llseek = test_llseek,   //用来修改文件当前的读写位置

  .read = test_read,              //从设备中同步读取数据

  .write = test_write,     //向设备发送数据

  .open = test_open,      //打开设备

  .ioctl = test_ioctl,              //执行设备I/O控制命令

  .release = test_release,       //关闭设备

};

本结构体在什么情况下使用?请解释结构体中各成员函数的作用,以及应用程序如何实现对这些接口的调用。

字符设备驱动中设备文件接口的结构体。创建相应的设备文件后,应用程序可以通过对设备文件的lseekreadwriteopenioctlclose实现对上述接口的调用。

7.        驱动编写过程中经常应注意设备的并发控制。

1)请举例说明驱动中需要注意并发控制的情况;

多个执行单元同时、并行被执行,而并发的执行单元对共享资源的访问导致竞争,

如多个进程打开了某个设备文件,并同时进行读写操作,则引发竞争。

 

2)linux中并发的常用技术有哪些?简要说明这些技术的区别。

自旋锁:互斥的,适用于短时间的,忙等待

信号量:多个持有者,也有互斥信号量,睡眠,可适用于慢操作

8.        在CPU的接口中,经常有用到SPI、I2C等设备与CPU的接口,你的项目中是否有使用过这类接口?如果有,请选择其一说明它在你的系统中的作用。

9.        阅读以下资料并回答问题

The TLV320AIC23B is a high-performance stereo audiocodec with highly integrated analog functionality. The analog-to-digitalconverters (ADCs) and digital-to-analog converters (DACs) within theTLV320AIC23B use multibit sigma-delta technology with integrated oversamplingdigital interpolation filters. Data-transfer word lengths of 16, 20, 24, and 32bits, with sample rates from 8 kHz to 96 kHz, are supported. The ADCsigma-delta modulator features third-order multibit architecture with up to90-dBA signal-to-noise ratio (SNR) at audio sampling rates up to 96 kHz, enablinghigh-fidelity audio recording in a compact, power-saving design. The DACsigma-delta modulator features a second-order multibit architecture with up to100-dBA SNR at audio sampling rates up to 96 kHz, enabling high-quality digitalaudio-playback capability, while consuming less than 23 mW during playbackonly. The TLV320AIC23B is the ideal analog input/output (I/O) choice forportable digital audio-player and recorder applications, such as MP3 digitalaudio players.

The TLV320AIC23B has the following set ofregisters, which are used to program the modes of operation.

Register Map:

 

 

Left line input channel volume control (Address:0000000)

 

 

1)  重新复位寄存器,可能需要对哪个地址的寄存器进行设置?设置数字音频接口格式,需要用到哪个地址的寄存器?

Address0001111寄存器

Address0000111寄存器

2)目前需要对TLV320AIC23B芯片左路输入进行音量调节的控制,需要如何设置寄存器的值?请分别编写逐步进行音量增大和减小控制的函数(每次函数调用变化一格音量,操作时不可影响到其他与音量无关位的数据,寄存器位数为32位,程序运行处理器为小端模式)。

主要需要操作的是1:地址为0000000的寄存器LIM位要设为0 Normal;2:对0000000地址的寄存器的低5位D4~D0位进行加和减操作,对应调节音量大小。注意音量最大值和最小值的判断。根据操作是否针对D4~D0操作酌情给分。

10.     在linux驱动开发工作中,涉及到的知识包括驱动开发模式、内核相关知识和硬件相关知识几个方面,谈谈你对这几方面的认识以及你的掌握情况。

 

 

11.   TTL电平与RS232电平有什么区别?硬件上如何实现转换?

 

18. 

Node * ReverseList(Node *head) //链表逆序
{
if ( head == NULL || head->next == NULL )
return head;
Node *p1 = head ;
Node *p2 = p1->next ;
Node *p3 = p2->next ;
p1->next = NULL ;
while ( p3 != NULL )
{
p2->next = p1 ;
p1 = p2 ;
p2 = p3 ;
p3 = p3->next ;
}
p2->next = p1 ;
head = p2 ;
return head ;
}