移動計算機面試問題經驗

學識都 人氣:1.76W

C語言考查的重點一般是:指針、結構體、條件編譯、全局變量/局部變量。以下是

移動計算機面試問題經驗

我遇見過的面試問題:

1)請說一下extern C的作用(漢略)

Extern “C”是由C++提供的一個連接交換指定符號,用於告訴C++這段代碼是C函數。這是因爲C++編譯後庫中函數名會變得很長,與C生成的不一致,造成C++不能直接調用C函數,加上extren “c”後,C++就能直接調用C函數了。

Extern “C”主要使用正規DLL函數的引用和導出和 在C++包含C函數或C頭文件時使用。使用時在前面加上extern “c” 關鍵字即可

extern是C/C++語言中表明函數和全局變量作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本模塊或其它模塊中使用。記住,下列語句:

extern int a;

僅僅是一個變量的聲明,其並不是在定義變量a,並未爲a分配內存空間。變量a在所有模塊中作爲一種全局變量只能被定義一次,否則會出現連接錯誤。

通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變量以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變量和函數時只需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是並不會報錯;它會在連接階段中從模塊A編譯生成的目標代碼中找到此函數。(

一、修飾名(Decorated Name)

C/C++程序中的函數在內部是通過修飾名來標識的。修飾名是在函數定義或原型編譯階段由編譯器創建字符串。當你在LINK等工具中要指定一個函數名時,會用到修飾名。

1、使用修飾名:

大多數情況下,你不必知道函數的修飾名是什麼。連接器等工具通常都能處理函數未修飾的名字。然而,在有些情況下,你可能需要指定函數的修飾名。對於C++重載函數和特定的成員函數(如:構造函數和析構函數),你必須指定這些函數的修飾名,以便連接器等工具能夠匹配名字。同時,你也必須在那些引用c或c++函數名的彙編源文件中使用修飾名。

2、查看修飾名:

如果你編譯了一個源文件,該源文件中包含了函數定義或原型,你可以獲得函數的修飾名形式。

(1)用編譯器列表(compiler listing)來查看:

(i)通過將列表文件類型編譯器選項(/FA[c|s]) 設置爲下面中的一種,來產生列表文件:Assembly with Machine Code (/FAc); Assembly with Source Code (/FAs); Assembly, Machine Code, and Source (/FAcs).

(ii)在產生的列表文件中,找到包含未經修飾的函數定義的行。

(iii)查找前面一行。PROC NEAR 命令標籤前就是函數名經過修飾後的形式。

(2)使用DUMPBIN工具來查看:

在或上運行DUMPBIN,使用/SYMBOLS選項。在輸出中查找未經修飾的函數定義。後面跟着的就是經過修飾的函數名,用圓括號括起來的。

二、替代連接說明:

如果在c++中編寫一個程序需要用到c的庫,那該如何?如果這樣聲明一個c函數:

void f(int a,char b);

c++編譯器就會將這個名字變成相應的修飾名,比如:?f@@YAXHD@Z。

然而,c編譯器編譯的庫的內部函數名(連接器使用)是完全不同的。這樣,當c++連接器連接c的函數庫時,將會產生內部使用函數不匹配。

故,c++中提供了一個替代連接說明(alternate linkage specification),它是通過重載extern關鍵字來實現的。

extern後跟一個字符串來指定想聲明的函數的連接類型,後面是函數聲明,比如:

extern "C" void f(int a,char b);

這樣,就是告訴編譯器是c連接,這樣就不會轉換函數名了。此例中,編譯後的內部函數名是_f。

2)請說一下#ifdef...的作用(漢略)

#ifdef的作用大體上是工程功能的切換,通常是根據某些宏是否定義來決定是否啓用某些功能。比如網絡監控系統,通過宏的切換,可以實現平臺的移植,視屏路數的定義,雲臺、矩陣和透明串口的切換,等等。由於#ifdef的存在,靜態配置一下參數即可讓firmware實現不同的功能。

1.利用#ifdef/#endif將某程序功能模塊包括進去,以向某用戶提供該功能。

在程序首部定義#ifdef HNLD:

#ifdef HNLD

include"n166_hn.c"

#endif

如果不許向別的用戶提供該功能,則在編譯之前將首部的HNLD加一下劃線即可。

2.在每一個子程序前加上標記,以便追蹤程序的運行。

#ifdef DEBUG

printf(" Now is in hunan !");

#endif

3.避開硬件的限制。有時一些具體應用環境的硬件不一樣,但限於條件,本地缺乏這種設備,於是繞過硬件,直接寫出預期結果。具體做法是:

#ifndef TEST

i=dial();

//程序調試運行時繞過此語句

#else

i=0;

#endif

調試通過後,再屏蔽TEST的定義並重新編譯,即可發給用戶使用了。

3)C語言裏,哪些變量是存放在堆裏,哪些是存放在棧裏?(普天)

heap area存放程序的動態數據

stack area存放程序的局部數據

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

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

4)C語言裏的static關鍵詞是什麼含義?(普天)

與extern對應的關鍵字是static,被它修飾的全局變量和函數只能在本模塊中使用。因此,一個函數或變量只可能被本模塊使用時,其不可能被extern “C”修飾。

5)進程和線程有什麼區別?(普天)

線程的引入:例如,有一個Web服務器要進程的方式併發地處理來自不同用戶的網頁訪問請求的話,可以創建父進程和多個子進程的方式來進行處理,但是創建一個進程要花費較大的系統開銷和佔用較多的資源。除外,這些不同的用戶子進程在執行的時候涉及到進程上下文切換,上下文切換是一個複雜的過程。所以,爲了減少進程切換和創建的開銷,提高執行效率和節省資源,人們在操作系統中引入了"線程(thread)"的概念。

進程的作用和定義:進程是爲了提高CPU的執行效率,減少因爲程序等待帶來的CPU空轉以及其他計算機軟硬件資源的浪費而提出來的`。進程是爲了完成用戶任務所需要的程序的一次執行過程和爲其分配資源的一個基本單位,是一個具有獨立功能的程序段對某個數據集的一次執行活動。

線程和進程的區別:

1、線程是進程的一部分,所以線程有的時候被稱爲是輕權進程或者輕量級進程。

2、一個沒有線程的進程是可以被看作單線程的,如果一個進程內擁有多個進程,進程的執行過程不是一條線(線程)的,而是多條線(線程)共同完成的。

3、系統在運行的時候會爲每個進程分配不同的內存區域,但是不會爲線程分配內存(線程所使用的資源是它所屬的進程的資源),線程組只能共享資源。那就是說,出了CPU之外(線程在運行的時候要佔用CPU資源),計算機內部的軟硬件資源的分配與線程無關,線程只能共享它所屬進程的資源。

4、與進程的控制表PCB相似,線程也有自己的控制表TCB,但是TCB中所保存的線程狀態比PCB表中少多了。

5、進程是系統所有資源分配時候的一個基本單位,擁有一個完整的虛擬空間地址,並不依賴線程而獨立存在。

進程與程序的區別:

程序是一組指令的集合,它是靜態的實體,沒有執行的含義。而進程是一個動態的實體,有自己的生命週期。一般說來,一個進程肯定與一個程序相對應,並且只有一個,但是一個程序可以有多個進程,或者一個進程都沒有。除此之外,進程還有併發性和交往性。簡單地說,進程是程序的一部分,程序運行的時候會產生進程。

總結:

線程是進程的一部分,進程是程序的一部分