嵌入式經典筆試?

嵌入式入職的要求可以說挺高的,下面是我總結的嵌入式經典筆試題,希望可以幫助到大家。

工具/原料

網絡 WORD

方法/步驟

下面是個人認為嵌入式筆試中,答題捲上頻率比較高的知識點和案例,如果不對之處,希望大家多多指點批評

第一章C語言常見問題

1.1關作鍵字static的用

這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:

1)在函數體內,一個被聲明為靜態的變量在這一函數被調用過程中維持其值不變(該變量存放在靜態變量區)。

2)在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。

3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地範圍內使用。

大多數應試者能正確回答第一部分,一部分能正確回答第二部分,但是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,

因為他顯然不懂得本地化數據和代碼範圍的好處和重要性。

考點:在嵌入式系統中,要時刻懂得移植的重要性,程序可能是很多程序員共同協作同時完成,在定義變量及函數的過程,可能會重名,這給系統的集成帶來麻煩,因此保證不衝突的辦法是顯示的表示此變量或者函數是本地的,static即可。

在Linux的模塊編程中,這一條很明顯,所有的函數和全局變量都要用static關鍵字聲明,將其作用域限制在本模塊內部,與其他模塊共享的函數或者變量要EXPORT到內核中。

1)設置變量的存儲域,函數體內static變量的作用範圍為該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;

(2)限制變量的作用域,在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;

(3)限制函數的作用域,在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內;

(4)在類中的static成員變量意味著它為該類的所有實例所共享,也就是說當某個類的實例修改了該靜態成員變量,其修改值為該類的其它所有實例所見;

(5)在類中的static成員函數屬於整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。

1.2程序運行時的內存分配

一個由C/C++編譯的程序佔用的內存分為以下幾個部分

1、棧區(stack)—由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。

2、堆區(heap)—一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式類似於鏈表。

3、全局區(靜態區)(static)—全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束後由系統釋放。

4、文字常量區—常量字符串就是放在這裡的。程序結束後由系統釋放

5、程序代碼區—存放函數體的二進制代碼。

二、例子程序

這是一個前輩寫的,非常詳細

//main.cpp

int a = 0;全局初始化區

char *p1;全局未初始化區

main()

{

int b;棧

char s[] ="abc";棧

char *p2;棧

char *p3 ="123456"; 123456\0在常量區,p3在棧上。

static int c =0;全局(靜態)初始化區

p1 = (char*)malloc(10);

p2 = (char*)malloc(20);分配得來得10和20字節的區域就在堆區。

strcpy(p1,"123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。

}

1.3堆和棧的區別

1)申請方式

stack:

由系統自動分配。例如,聲明在函數中一個局部變量int b;系統自動在棧中為b開闢空間

heap:

需要程序員自己申請,並指明大小,在c中malloc函數

如p1 = (char *)malloc(10);

在C++中用new運算符

如p2 = (char *)malloc(10);

但是注意p1、p2本身是在棧中的。

堆是向上增長而棧是向下增長

2)堆棧的進一步討論

在學習《深入理解計算機系統》中鏈接這一章中,數據講一個可執行文件包含多個段。在Linux系統中代碼段總是從0x08048000處開始,數據段在接下來的4KB對齊的地址處,運行時堆在接下來的讀寫段之後的第一個4KB對齊的地址處,

並通過調用malloc庫網上增長,開始於地址0x40000000處的段是為共享庫保留的,用戶棧總是從地址0xbfffffff處開始,並向下增長,從棧的上部開始於地址0xc0000000處的段是為操作系統駐留存儲器部分的代碼和數據保留的。如下圖:

下面通過代碼來測試:

#include

int a1=0;

staticintsa=0;

int a2=0;

int b;

int main()

{

int c1=1;

int c2;

int *d=(int *)malloc(sizeof(int)*10);

int *e=(int *)malloc(sizeof(int)*10);

staticint f=0;

if(d==NULL)

{

printf("malloc error");

return -1;

}

printf("a1:%p\n",&a1);

printf("sa:%p\n",&sa);

printf("a2:%p\n",&a2);

printf("b:%p\n",&b);

printf("c1:%p\n",&c1);

printf("c2:%p\n",&c2);

printf("d:%p\n",&d);

printf("*d:%p\n",d);

printf("e:%p\n",&e);

printf("*e:%p\n",e);

printf("f:%p\n",&f);

printf("%p\n",&"123");

free(d);

return 0;

}

分析如下:

a1,a2,sa,f是按序存放,且全局共有非靜態變量和靜態變量是分開存放的,緊接著存放的是全局非初始化變量b,由於是int型,故地址相差4.

c1,c2,d,e這幾個變量存儲在用戶棧空間。主要區分d、e和d、e申請內存之間的區別。

*d,*e代表申請的內存,地址是增大方向,即地址是向上增長的,為堆中申請的數據。

“123”為常量,地址0x80486da應該在只讀段的範圍內,屬於rodate數據。

故可知:C程序中,全局變量和靜態變量存儲在讀寫段,常量存儲在制度段,動態申請的內容是在堆上,局部變量在運行時棧中。

1.4關鍵字const的含義

只要能說出const意味著"只讀"就可以了。儘管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)

如果應試者能正確回答這個問題,我將問他一個附加的問題:下面的聲明都是什麼意思?

Const只是一個修飾符,不管怎麼樣a仍然是一個int型的變量

constint a;

int const a;

constint *a;

int * const a;

int const * aconst;

本質:const在誰後面誰就不可修改,const在最前面則將其後移一位即可,二者等效

前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指針(也就是,指向的整型數是不可修改的,但指針可以,此最常見於函數的參數,當你只引用傳進來指針所指向的值時應該加上const修飾符,程序中修改編譯就不通過,可以減少程序的bug)。

第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味著a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。

const關鍵字至少有下列n個作用:

(1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因為以後就沒有機會再去改變它了;

(2)對指針來說,可以指定指針本身為const,也可以指定指針所指的數據為const,或二者同時指定為const;

(3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;

(4)對於類的成員函數,若指定其為const類型,則表明其是一個常函數,不能修改類的成員變量;

(5)對於類的成員函數,有時候必須指定其返回值為const類型,以使得其返回值不為“左值”。例如:

constclassAoperator*(const classA& a1,const classA& a2);

operator*的返回結果必須是一個const對象。如果不是,這樣的變態代碼也不會編譯出錯:

classA a, b, c;

(a * b) = c; //對a*b的結果賦值

  操作(a * b) = c顯然不符合編程者的初衷,也沒有任何意義。

1.5關鍵字volatile含義

一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裡的備份。下面是volatile變量的幾個例子:

1.6什麼是野指針?產生的原因?

“野指針”不是NULL指針,是指向“垃圾”內存(不可用內存)的指針。“野指針”是很危險的,if無法判斷一個指針是正常指針還是“野指針”。有個良好的編程習慣是避免“野指針”的唯一方法。

野指針的成因主要有三種:

一、指針變量沒有被初始化。指針變量在創建的同時應當被初始化,要麼將指針設置為NULL,要麼讓它指向合法的內存。

二、指針p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指針。

三、指針操作超越了變量的作用範圍。比如不要返回指向棧內存的指針或引用,因為棧內存在函數結束時會被釋放。比如說某個地址的生命期,使用一個沒有生命期的指針是非常危險的。

1.7 sizeof和strlen區別

一、sizeof

sizeof(...)是運算符,在頭文件中typedef為unsigned int,其值在編譯時即計算好了,參數可以是數組、指針、類型、對象、函數等。它的功能是:獲得保證能容納實現所建立的最大對象的字節大小。

二、strlen

strlen(...)是函數,要在運行時才能計算。參數必須是字符型指針(char*)。當數組名作為參數傳入時,實際上數組就退化成指針了。

它的功能是:返回字符串的長度。該字符串可能是自己定義的,也可能是內存中隨機的,該函數實際完成的功能是從代表該字符串的第一個地址開始遍歷,直到遇到結束符NULL。返回的長度大小不包括NULL。

三、舉例:

eg1、char arr[10] = "What?";

intlen_one =strlen(arr);

intlen_two =sizeof(arr);

cout<

輸出結果為:5 and 10

點評:sizeof返回定義arr數組時,編譯器為其分配的數組空間大小,不關心裡面存了多少數據。strlen只關心存儲的數據內容,不關心空間的大小和類型。其中\0不計入strlen計數中去。

第二章 C語言的常見筆試題

2.1 在某工程中,要求設置一絕對地址為

嵌入式系統經常具有要求程序員去訪問某特定的內存位置的特點。在某工程中,要求設置一絕對地址為0x67a9的整型變量的值為0xaa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務。

int*ptr;

ptr =(int *)0x67a9;

*ptr =0xaa55;

2.2 寫出strcpy,strcmp,strlen,memcpy函數源碼的實現。

char * strcpy( char*strDest, const char *strSrc )

{

assert( (strDest !=NULL) && (strSrc != NULL) );

char *address =strDest;

while( (*strDest++= * strSrc++) !=‘\0’ );

return address;

}

intstrlen( constchar *str ) //輸入參數const

{

assert(strt != NULL); //斷言字符串地址非0

intlen;

while( (*str++) !='\0' )

{

len++;

}

returnlen;

}

2.3 請寫一個C函數,判斷大小端。

所謂的大端模式,是指數據的高位,保存在內存的低地址中,而數據的低位,保存在內存的高地址中

所謂的小端模式,是指數據的高位保存在內存的高地址中,而數據的低位保存在內存的低地址中

intcheckCPU()

{

{

union w

{

int a;

char b;

} c;

c.a = 1;

return (c.b == 1);

}

}

2.4用變量a 給出下面的定義

a) 一個整型數(An integer)

b)一個指向整型數的指針(A pointer to an integer)

c)一個指向指針的的指針,它指向的指針是指向一個整型數(A pointer to a pointer to anintege)r

d)一個有10 個整型數的數組(An array of 10 integers)

e) 一個有10 個指針的數組,該指針是指向一個整型數的。(An array of 10 pointers tointegers)

f) 一個指向有10 個整型數數組的指針(A pointer to an array of 10integers)

g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer asan argument

and returns an integer)

h)一個有10 個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數(An array of ten pointers tofunctions t

hat take an integer argument and return aninteger )

答案是:

a) int a; // An integer

b) int *a; // A pointer to an integer

c) int **a; // A pointer to a pointer to aninteger

d) int a[10]; // An array of 10 integers

e) int *a[10]; // An array of 10 pointers to integers

f) int (*a)[10]; // A pointer to an array of 10integers

g) int (*a)(int); // A pointer to a function athat takes an integer argument and returns an integer

h) int (*a[10])(int); // An array of 10 pointersto functions that take an integer argument and return an integer

2.5 位操作

嵌入式系統總是要用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設置a的bit 3,第二個清除a的bit 3。在以上兩個操作中,要保持其它位不變。

#define BIT3 (0x1 << 3)

staticint a;

void set_bit3(void) {

a = BIT3;

}

void clear_bit3(void) {

a&= ~BIT3;

}#define BIT3 (0x1 << 3)

staticint a;

void set_bit3(void) {

a = BIT3;

}

void clear_bit3(void) {

a&= ~BIT3;

}

2.6 與“零值”比較

分別給出BOOL,int,float,指針變量與“零值”比較的 if語句(假設變量名為var)

解答:

BOOL 型變量:if(!var)

int型變量:if(var==0)

float 型變量:

const floatEPSINON = 0.00001;

if ((x >= -EPSINON) && (x <= EPSINON)

指針變量:if(var==NULL)

2.7 對齊方式

·使用偽指令#pragma pack (n),編譯器將按照n 個字節對齊;

·使用偽指令#pragma pack (),取消自定義字節對齊方式。

注意:如果#pragma pack (n)中指定的n 大於結構體中最大成員的size,則其不起作用,結構體仍然按照size 最大的成員進行對界。

另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n 字節邊界上。

2.8 malloc分配的是物理地址還是虛擬地址

物理地址

2.9 不是使用變量,調換兩個變量的值

int a=10,b=20;a=a+b;b=a-b;a=a-b;結果:a=20;b=10;

第三章 C++常見問題

1. memcpy源碼

void * memcpy (

void * dst,

const void * src,

size_t count ){

void * ret = dst;

if((dst == NULL) (src == NULL) (count== 0))

return NULL;

while (count--) {

*(char *)dst = *(char *)src;

dst = (char *)dst + 1;

src = (char *)src + 1;

}

return(ret);

}

也許這並不是最佳答案,可是我也懶不想寫太多,至少應該轉換成int這樣可以提供效率。

2. 冒泡排序

#define LEN 8

int a[LEN]={5,4,3,2,1,7,6,0};

intbubble_new_sort(void)

{

int i=0; int j = 0; int k = 8; int flage = 1; int tmp =0;

for(i=1;(i

flage = 0;

for(j=0;j

if(a[j]>a[j+1]){

tmp =a[j];

a[j] = a[j+1];

a[j+1] = tmp;

flage=1 ;

}

}

printf("i = %d : %d,%d,%d,%d,%d,%d,%d,%d\n",i,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]);

}

printf("%d,%d,%d,%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]);

return 0;

}

3. 進程和線程的區別

進程是表示資源分配的基本單位,又是調度運行的基本單位。

線程是進程中執行運算的最小單位,亦即執行處理機調度的基本單位。

4. const char * char * const

5. 請問C++的類和C 裡面的struct 有什麼區別?

c++中的類具有成員保護功能,並且具有繼承,多態這類oo特點,而c 裡的struct 沒有

6. 交換兩個數,不用第三塊兒內存:

int a = 2;

int b = 3

a = a + b;

b = a - b;

a = a - b;

或者:

a = a ^ b;

b = a ^ b;

a = a ^ b;

7. 二分查找思想

int binary_search(int* a, int len, int goal)

{

int low = 0;

int high = len - 1;

while(low <= high)

{

int middle = (low +high)/2;

if(a[middle] == goal)

return middle; //在左半邊

else if(a[middle] >goal)

high = middle - 1;//在右半邊

else

low = middle + 1;

}

return -1; //沒找到

}

8. free

一個指針被free 後 內存被釋放,但並不是空的,指向的位置不確定。

第五章 C&C++

5.1 C和C++做程序的區別?

1.C是一個結構化語言,它的重點在於算法和數據結構。C程序的設計首要考慮的是如何通過一個過程,對輸入(或環境條件)進行運算處理得到輸出(或實現過程(事務)控制)。

2.C++,首要考慮的是如何構造一個對象模型,讓這個模型能夠契合與之對應的問題域,這樣就可以通過獲取對象的狀態信息得到輸出或實現過程(事務)控制。所以C與C++的最大區別在於它們的用於解決問題的思想方法不一樣。之所以說C++比C更先進,是因為“設計這個概念已經被融入到C++之中”。

嵌入式經典筆試

相關問題答案