天天看點

嵌入式筆試面試題(10)----修飾符(define typedef static 等)

1、#include "stdafx.h"

#define SQR(X) X*X

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

{

  int a = 10;

  int k = 2;

  int m = 1;

  a /= SQR(k+m)/SQR(k+m); 

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

  return 0;//1

2、const 符号常量;

(1)const char *p

(2)char const *p

(3)char * const p

說明上面三種描述的差別;

(1)P可變,p指向内容不可變;

(2)P可變,p指向内容不可變;

(3)P不可變,p指向内容可變;

3、static變量和static 函數各有什麼特點?

Static變量在函數中修飾局部變量,該函數調用完成後,記憶體不被釋放,延長變量生命周期;

Static修飾全局變量,該變量作用域隻在本文本中有效,如果其他文本中有同名變量不會影響;

Static修飾函數,該函數作用域隻在本文本中有效,其他文本中有同名函數互不影響;

4、請給出如下程式的結果

#define MAX_NUM 100+200

int nTemp = MAX_NUM*10;

則Temp = 2100

5、宏的應用:

用宏聲明一個常數,用來表示1年中有多少秒(忽略閏年的問題)

#define SECONDS_PER_YEAR 365*24*60*60(UL)

寫一個宏:這個宏輸入連個參數并傳回較小的一個

用宏來選擇不同的代碼段

#define MIN(x,y)   (((x)<(y)) ?(x):(y))

6、關鍵字static const volatile 分别的作用是什麼?

在C語言中,關鍵字static有三個明顯的作用:

1). 在函數體,一個被聲明為靜态的變量在這一函數被調用結束後不釋放其存儲空間。定義為static的局部變量的存儲在全局區(靜态區)而一般的局部變量存儲在棧中。

2). 在子產品内(但在函數體外),一個被聲明為靜态的變量可以被子產品内所用函數通路,但不能被子產品外其它函數通路。它是一個本地的全局變量。

3). 在子產品内,一個被聲明為靜态的函數隻可被這一子產品内的其它函數調用。那就是,這個函數被限制在聲明它的子產品的本地範圍内使用。

4). 類中定義的static資料成員屬于所有該類對象共享,在記憶體中隻占一份空間,而不是每個對象都分别為它保留一份空間。

5).類中定義為static的成員函數隻能直接調用static資料成員,若要通路非靜态資料成員,需要加上對象名。因為靜态成員函數沒有this指針。

關鍵字const是什麼含意?

const意味着“隻讀”。

static和const關鍵字的作用可以從兩個方面回答:一是和類的成員函數或者成員變量相關,二是不屬于類的函數或者變量。

static關鍵字的作用:

1、函數體内static變量的作用範圍為該函數體,不同于auto變量,該變量的記憶體隻被配置設定一次,是以,其值在下次調用的時候仍然維持原始值,作用域是聲明該變量的代碼段中。

2、在子產品内的static全局變量可以被子產品内的所有函數通路,但是不能被子產品外的其他函數通路。

3、在子產品内的static函數隻可以被這一子產品内的其他函數調用,這個函數的使用範圍被限制在聲明它的子產品内。

4、在類中的static成員變量屬于整個類所有,對類的所有對象隻有一份拷貝。

5、在類中的static成員函數屬于整個類所有,這個函數不接受this指針,因而隻能通路類的static成員變量。

const關鍵字的作用:

1、想要阻止一個變量被改變,可以使用const關鍵字。在定義該const關鍵字是,通常要對它進行初始化,因為以後再也沒有機會去改變它。

2、對于指針來說,可以指定指針本省為const,也可以指定指針所指向的資料為const,或者二者同時指定為const。

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

4.對于類的成員函數,若指定為const,則表明其實一個常函數,不能修改類的成員變量。

5對于類的成員函數,有時候必須制定其傳回值為const,以使得其傳回值不能為左值。

關鍵字volatile有什麼含意

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

1). 并行裝置的硬體寄存器(如:狀态寄存器)

2). 一個中斷服務子程式中會通路到的非自動變量(Non-automatic variables)

3). 多線程應用中被幾個任務共享的變量

7、C語言中的變量根據其作用域來劃分,分成幾類?各自用在什麼地方?

8、下面的大小分别是多少?//4

Short *p;  short (*p)();    int p;  int **p;   int (*P)(int,int)

9、在C語言中,隻有在使用時才占用記憶體單元的變量,其存儲類型是()

A.auto register          B.extern register

C.auto static            D.static register 

//register是指寄存器變量,寄存器是cpu的存儲部件,即高速緩存,定義這個變量适用于頻繁修改(使用)的全局變量,以加快運作速度,因為儲存在寄存器中,省去了在記憶體中調用,定義這個變量後,不能取位址。

11、請寫出BOOL,float ,指針變量與“零值”比較的if語句。

布爾變量與零值比較

l 【規則4-3-1】不可将布爾變量直接與TRUE、FALSE或者1、0進行比較。 

根據布爾類型的語義,零值為“假”(記為FALSE),任何非零值都是“真”(記為TRUE)。TRUE的值究竟是什麼并沒有統一的标準。例如Visual   C++   将TRUE定義為1,而Visual   Basic則将TRUE定義為-1。 

假設布爾變量名字為flag,它與零值比較的标準if語句如下: 

if   (flag) //   表示flag為真 

if   (!flag) //   表示flag為假 

其它的用法都屬于不良風格,例如:

if   (flag   ==   TRUE) 

if   (flag   ==   1   ) 

if   (flag   ==   FALSE)       

if   (flag   ==   0) 

4.3.2   整型變量與零值比較 

l 【規則4-3-2】應當将整型變量用“==”或“!=”直接與0比較。 

假設整型變量的名字為value,它與零值比較的标準if語句如下: 

if   (value   ==   0)       

if   (value   !=   0) 

不可模仿布爾變量的風格而寫成

if   (value) //   會讓人誤解   value是布爾變量 

if   (!value)    

4.3.3   浮點變量與零值比較 

l 【規則4-3-3】不可将浮點變量用“==”或“!=”與任何數字比較。 

千萬要留意,無論是float還是double類型的變量,都有精度限制。是以一定要避免将浮點變量用“==”或“!=”與數字比較,應該設法轉化成“> =”或“ <=”形式。 

假設浮點變量的名字為x,應當将 

if   (x   ==   0.0)   //   隐含錯誤的比較 

轉化為

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

其中EPSINON是允許的誤差(即精度)。 

4.3.4   指針變量與零值比較 

l 【規則4-3-4】應當将指針變量用“==”或“!=”與NULL比較。 

指針變量的零值是“空”(記為NULL)。盡管NULL的值與0相同,但是兩者意義不同。假設指針變量的名字為p,它與零值比較的标準if語句如下: 

if   (p   ==   NULL) //   p與NULL顯式比較,強調p是指針變量 

if   (p   !=   NULL) 

不要寫成

if   (p   ==   0)   //   容易讓人誤解p是整型變量 

if   (p   !=   0)             

或者

if   (p) //   容易讓人誤解p是布爾變量 

if   (!p) 

4.3.5   對if語句的補充說明 

有時候我們可能會看到   if   (NULL   ==   p)   這樣古怪的格式。不是程式寫錯了,是程式員為了防止将   if   (p   ==   NULL)   誤寫成   if   (p   =   NULL),而有意把p和NULL颠倒。編譯器認為   if   (p   =   NULL)   是合法的,但是會指出   if   (NULL   =   p)是錯誤的,因為NULL不能被指派。 

程式中有時會遇到if/else/return的組合,應該将如下不良風格的程式 

if   (condition) 

return   x; 

return   y; 

改寫為

if   (condition) 

return   x; 

else 

return   y; 

或者改寫成更加簡練的

return   (condition   ?   x   :   y);

/*****************************************************************************************************************************************************************************************************/

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

解答:

    BOOL型變量:if(!var)

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

float型變量:

const float EPSINON = 0.00001;

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

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

剖析:

考查對0值判斷的“内功”,BOOL型變量的0判斷完全可以寫成if(var==0),而int型變量也可以寫成if(!var),指針變量的判斷也可以寫成if(!var),上述寫法雖然程式都能正确運作,但是未能清晰地表達程式的意思。一般的,如果想讓if判斷一個變量的“真”、“假”,應直接使用if(var)、if(!var),表明其為“邏輯”判斷;如果用if判斷一個數值型變量(short、int、long等),應該用if(var==0),表明是與0進行“數值”上的比較;而判斷指針則适宜用if(var==NULL),這是一種很好的程式設計習慣。

浮點型變量并不精确,是以不可将float變量用“==”或“!=”與數字比較,應該設法轉化成“>=”或“<=”形式。如果寫成if (x == 0.0),則判為錯

12、實作将一個整形資料進行反序,如123變成321,如果int a=0xAD 78 怎麼實作a的高地位反轉?

#include <string.h>

#include <stdio.h>

Void main()

{

   char buf[1024]={0};

   int a=0,i=0;

  printf(“please enter a string:”);

gets(buf);

a=strlen(buf);

for(i=a-1;a>=0;a--)

{

  Printf(“%c\n”,buf[i]);

}

Putchar(‘\n’);

}

13、define和typedef的差別:

(1) 執行時間不同:

Define在編譯之前,預處理階段原樣替換,簡單機械的字元串替換;

Typedef在編譯階段有效,在編譯階段,有類型檢查功能;

(2)功能差異:

           Typedef用來給類型的别名,常與struct結合使用;

           Define不隻可以為類型取别名,還可以定義常量,變量,編譯宏開關;

(3)作用域不同:

          Define沒有作用域限制,隻要之前預定過的宏,後面都可以使用;

          Typedef有作用域的限制;

14、以下程式的輸出結果是________.

#include     <stdio.h>

int fun(int   x,int  y)

{

  static  int   m = 0;

  static  int   i = 2;

  i += m + 1;

  m = i + x + y;

  return  m;

}

void main()

{

  int   j = 4;

  int   m = 1;

  int   k;

  k = fun(j, m);

  printf("%d,", k);//8

  k=fun(j, m);

  printf("%d\n", k);//17

  return;

}

15、定義函數時,預設函數的類型聲明,則函數類型取預設類型

A.void

B.char

C.float

D.int

16、若有宏定義:#define MOD(x,y) x%y  

則執行以下語句後的輸出結果是

int a=13,b=94;

printf(″%d\n″,MOD(b,a+4));

A.5

B.7

C.9

D.11

17、設

#define N 3

#define Y(n) ((N+1)*n)

則表達式2*(N+Y(5+1))的值是

A.42

B.48

C.54

D.出錯

19、如何判别一個數是unsigned。

 Int a;

Return (a>=0&&(~a>=0))    傳回為0,為有符号數;

Unsigned  a;

Return (a>=0&&(~a>=0))    傳回為1,為無符号數;

20、用#Define replace_bit(a, v, m, n)實作bit的替換,如:

a = 0b0101010101101100,若v = 1101,m = 2, n = 4, 則從第m個bit起将n個bit替換為v,若v的bit個數大于n, 則取前n個。

21、将無符号int的後n位bit傳回,用#Define_bit(value)實作,用宏定義實作。

22、unsigned int u;

for(u = 255;u >= 0; u - -)

{

Printf(u);

}

23、

unsigned a = 6;

int a = -20;

(a + b) > 6 ? puts(“>6”)

24、寫兩段代碼,完成:

将a的bit3設為1

将a的bit3清零

Int a;

a | 1<<3;

a & ~(1<<3);

25、全局變量、局部變量、靜态全局變量、靜态局部變量的差別和引用方式。

初始化的全局變量在.data段,可以外部文本加extern引用;

未初始化的全局變量在.bss段,可以外部文本加extern引用;

靜态全局變量差別是不能在外部檔案引用;

局部變量在運作時,棧區配置設定空間;

靜态局部變量在靜态區配置設定空間,函數調用後記憶體不釋放;

26、#define test struct

typedef struct test哪個更好

27、以下代碼的輸出結果是

#include <stdio.h>

#define SQR(x) (x*x)

void main

{

int a, b = 3;

a = SQR(b + 2);

printf(“/n%d”,a);

}//11

char *a 與char a[] 的差別

char *a = "hello" 中的a是指向第一個字元‘a'的一個指針

char a[20] = "hello" 中數組名a也是執行數組第一個字元‘h’的指針

但二者并不相同:

看執行個體:把兩個字元串相加:

結果:

對比:

結果:

把字元串加到指針所指的字串上去,出現段錯誤,本質原因:*d="0123456789"存放在常量區,是無法修的。而數組是存放在棧中,是可以修改的。兩者差別如下:

一. ”讀“ ”寫“ 能力

· char *a = "abcd";  此時"abcd"存放在常量區。通過指針隻可以通路字元串常量,而不可以改變它。

· 而char a[20] = "abcd"; 此時 "abcd"存放在棧。可以通過指針去通路和修改數組内容。

二. 指派時刻

· char *a = "abcd"; 是在編譯時就确定了(因為為常量)。

· 而char a[20] = "abcd"; 在運作時确定

三. 存取效率

· char *a = "abcd"; 存于靜态存儲區。在​​棧​​上的數組比指針所指向字元串快。是以慢

· 而char a[20] = "abcd"; 存于棧上。快

另外注意:

char a[] = "01234",雖然沒有指明字元串的長度,但是此時系統已經開好了,就是大小為6-----'0' '1' '2' '3' '4' '5' '\0',(注意strlen(a)是不計‘\0’)

看一結構中出現的同樣的問題:

這樣紅色部分在調用Init函數時會出現“Segment Default", 因為此時 指針n是靜态的,隻有“讀”的本事,不可以改變。

記憶體配置設定方式

記憶體配置設定有三種:靜态存儲區、堆區和棧區。他們的功能不同,對他們使用方式也就不同。