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;
}
(1)i、j定義時沒有初始化
(2)if() 中的 i ==1寫法不規範,如果誤寫為i=1,編譯仍通過,可邏輯不是預期的
(3)100 / par1時,沒有對除數進行非0檢查
(4)函數的輸入參數,最好寫為v_iPar1和v_cPar2,以表示是函數參數及各自的類型。(建議)
(5)if之後的大括弧,最好單獨一行。(建議)
13. 大端模式 / 小端/ 網路位元組序
(1) 什麼是大端模式,小端模式,網路位元組序。
嵌入式系統開發人員應該對Little-endian和Big-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和#endif把printf函數給包含起來,編譯的時候加上-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, //關閉裝置
};
本結構體在什麼情況下使用。請解釋結構體中各成員函數的作用,以及應用程式如何?對這些介面的調用。
字元裝置驅動中裝置檔案介面的結構體。建立相應的裝置檔案後,應用程式可以通過對裝置檔案的lseek、read、write、open、ioctl、close實現對上述介面的調用。
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) 重新複位寄存器,可能需要對哪個地址的寄存器進行設定。設定數字音頻介面格式,需要用到哪個地址的寄存器。
Address:0001111寄存器
Address:0000111寄存器
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 ;
}