隨筆 - 11  文章 - 2  trackbacks - 0
          <2008年11月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          新聞分類

          link

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          昨天突然決定開(kāi)始寫(xiě)博客,于是今天就開(kāi)始寫(xiě)了,也不知道怎么寫(xiě),就這樣吧先。。。
          posted @ 2010-02-25 21:29 poower 閱讀(142) | 評(píng)論 (0)編輯 收藏
          #!/bin/ksh
          DATE=`date +%Y%m%d`

          export ORACLE_HOME=/oracle/app/db
          export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"


          DATE=`date +%Y%m%d`

          /oracle/app/db/bin/exp boss_v2/ owner=boss_v2 compress=n direct=y recordlength=65535 file=./boss_v2$DATE.dmp log=./log/boss_v2$DATE.log
          if [ -f boss_v2$DATE.dmp ]
          then
            rm -f old.dmp
            mv new.dmp old.dmp
            mv boss_v2$DATE.dmp new.dmp
          fi   
          posted @ 2009-12-11 13:57 poower 閱讀(200) | 評(píng)論 (2)編輯 收藏
          另外,FireFox收藏夾(書(shū)簽)也可以通過(guò)菜單選項(xiàng)直接導(dǎo)出,具體方法是:打開(kāi)Firefox,點(diǎn)擊“書(shū)簽 -> 書(shū)簽管理”啟動(dòng)書(shū)簽管理器,點(diǎn)擊“文件 -> 導(dǎo)出”來(lái)備份現(xiàn)有的書(shū)簽。在另一臺(tái)機(jī)器上,再用書(shū)簽的“導(dǎo)入”功能把備份的書(shū)簽導(dǎo)入到新的Firefox的配置中即可。
          posted @ 2009-11-20 21:34 poower 閱讀(172) | 評(píng)論 (0)編輯 收藏

          輕松面試找到理想員工-非官方的面試技術(shù)指南

          簡(jiǎn)述:

          本文作者Joel Spolsky 是紐約市一家軟件公司Fog Creek Software的創(chuàng)始人。他畢業(yè)于耶魯大學(xué),曾分別在美國(guó)微軟、Viacom、Juno等公司任軟件設(shè)計(jì)師、經(jīng)理職位。本文來(lái)自于《祖兒談軟件》,文章原名為《輕松面試找到理想員工——非官方的面試技術(shù)指南》,作者最初本意是針?/p>

          作者:周思博 (Joel Spolsky   更新日期:2005-05-22
          來(lái)源:chinese.joelonsoftware.com   瀏覽次數(shù):

          譯: Chen Bin    編輯: Rick Ju    2000年3月23日

          雇傭合適的人對(duì)于Fog Creek軟件公司來(lái)說(shuō)是非常關(guān)鍵的。在我們這個(gè)領(lǐng)域,有三類人可以挑選。在一個(gè)極端, 是哪些混進(jìn)來(lái)的, 甚至缺乏最基本的工作技巧. 只要問(wèn)這類人兩三個(gè)簡(jiǎn)單的問(wèn)題,再讀一下他們的簡(jiǎn)歷,就可以輕易地剔除他們。另一個(gè)極端的類型是 才華橫溢的超級(jí)明星 這些人僅僅為了好玩就用匯編語(yǔ)言為Palm Pilot(一種手掌電腦)寫(xiě)了一個(gè)Lisp(一種人工智能編程語(yǔ)言)編譯器。在這兩種極端類型中間的是一大群不能確定水平的候選者,也許他們中的某些人能干些什么?這里的關(guān)鍵是明白超級(jí)明星和那一大堆屬于中間類型的人的區(qū)別,因?yàn)镕og Creek軟件公司只雇傭超級(jí)明星。下面我要介紹一些找出超級(jí)明星的技巧。

          Fog Creek公司最重要的雇傭標(biāo)準(zhǔn)是:

          有頭腦, 并且
          完成工作

          就是這些了。符合這樣標(biāo)準(zhǔn)的人就是我們公司需要的員工了。 記住這條標(biāo)準(zhǔn)。 每天上床前背誦這條標(biāo)準(zhǔn)。我們公司的目標(biāo)之一就是雇傭擁有這樣的潛質(zhì)的人,而不是雇傭懂某些技術(shù)的人。任何人所擁有的某些具體技術(shù)都會(huì)在幾年內(nèi)過(guò)時(shí),所以,雇傭有能力學(xué)習(xí)新技術(shù)的人,要比雇傭那些只在這一分鐘知道SQL編程是怎么回事的人對(duì)公司更劃算一點(diǎn)。

          有頭腦確實(shí)是一個(gè)很難定義的品質(zhì)。但是讓我們看一些在面試時(shí)能提問(wèn)的一些問(wèn)題,通過(guò)這些提問(wèn),我們可以找出擁有這種品質(zhì)的人。完成工作非常關(guān)鍵??雌饋?lái)有頭腦但是不能完成工作的人經(jīng)常擁有博士學(xué)位,在大公司工作過(guò),但是在公司中沒(méi)有人聽(tīng)他們的建議,因?yàn)樗麄兪峭耆撾x實(shí)際的。比起準(zhǔn)時(shí)交活兒,他們寧愿對(duì)于一些學(xué)院派的東西沉思。這些人由以下特性而可以識(shí)別出來(lái)。他們總是愛(ài)指出兩個(gè)根本不同的概念間的相似性。例如,他們會(huì)說(shuō)“Spreadsheets是一種特殊的編程語(yǔ)言”,然后花一個(gè)禮拜寫(xiě)一篇?jiǎng)尤说?,智慧的白皮?shū)。這篇白皮書(shū)論述了,作為一個(gè)編程語(yǔ)言,spreadsheet關(guān)于計(jì)算語(yǔ)言特性的方方面面。聰明,但是沒(méi)用。

          現(xiàn)在,我們來(lái)談?wù)?strong>完成工作但是沒(méi)有頭腦的人。他們愛(ài)做蠢事。從來(lái)也沒(méi)有考慮過(guò)將來(lái)得靠他們自己或者別的什么人來(lái)亡羊補(bǔ)牢。通過(guò)制造新的工作,他們成為了公司的負(fù)債而不是資產(chǎn)。因?yàn)樗麄儾粌H沒(méi)有為公司貢獻(xiàn)價(jià)值,還浪費(fèi)了好員工的時(shí)間。這些人通常到處粘貼大堆的代碼,而不愿意寫(xiě)子程序。他們是完成了工作,但是不是以最聰明的方式完成工作。

          面試時(shí)最重要的法則是:

          做決定

          在面試結(jié)束時(shí),對(duì)于被面試者,你不得不做一個(gè)直截了當(dāng)?shù)臎Q定。這個(gè)決定只有兩個(gè)結(jié)果:雇傭或者不雇傭. 回到你的電腦前,立刻用電子郵件通知招聘負(fù)責(zé)人你的決定。電子郵件的主題應(yīng)該是雇傭或者不雇傭。接著你需要在正文中寫(xiě)兩段來(lái)支持你的決定.

          沒(méi)有其他的答案。永遠(yuǎn)不要說(shuō),“雇傭你,但是不能在我的團(tuán)隊(duì)中”。這是非常粗魯?shù)?,因?yàn)槟阍诎凳緫?yīng)試者沒(méi)有聰明到能有和你一起工作的資格,但是以他的頭腦適合進(jìn)入那些天生輸家隊(duì)伍。如果你發(fā)覺(jué)自己被誘惑,想說(shuō)出那句“雇傭你,但是不能在我的隊(duì)伍中”,那么就簡(jiǎn)單的把這句話變成“不雇傭”再說(shuō)出口。這樣就沒(méi)事了。甚至如果某個(gè)人在特定領(lǐng)域很能干,但是在別的隊(duì)伍中將會(huì)表現(xiàn)不好,也是不雇傭。事物變化的如此之快,我們需要的是在任何地方都能成功的人。如果某些情況下你發(fā)現(xiàn)了一個(gè)白癡專家(擁有某些特殊能力的白癡),這個(gè)專家對(duì)于SQL非常,非常,非常的精通,但是除此之外什么也學(xué)不會(huì),不雇傭。在Fog Creek公司他們沒(méi)有將來(lái)。

          永遠(yuǎn)不要說(shuō),“也許,我吃不準(zhǔn)”。如果你吃不準(zhǔn),意味著不雇傭???,比你想象的容易的多。吃不準(zhǔn)?就說(shuō)不!同樣,如果你不能作出決定,那意味著不雇傭。不要說(shuō),”嗯,雇傭,我想是這樣的。但是關(guān)于...,我想知道 ...”。這種情況就是不雇傭

          最重要的是記住這點(diǎn),放棄一個(gè)可能的好人要比招進(jìn)一個(gè)壞人強(qiáng)(譯者按:中國(guó)有位哲人說(shuō)過(guò),寧可錯(cuò)殺一千,不可放過(guò)一個(gè),呵呵)。一個(gè)不合格的求職者如果進(jìn)入了公司,將要消耗公司大量的金錢(qián)和精力。其他優(yōu)秀員工的還要浪費(fèi)時(shí)間來(lái)修復(fù)這個(gè)人的錯(cuò)誤。如果現(xiàn)在你還在猶豫,不雇傭

          如果你是Fog Creek公司的面試官,當(dāng)你拒絕了大量的應(yīng)聘者時(shí),不要為Fog Creek公司將因此雇不到任何人了而憂慮。這不是你的問(wèn)題。這是招聘負(fù)責(zé)人的問(wèn)題。這是人力資源部的問(wèn)題。這是Joel(譯者注: Fog Creek公司的老板,本文作者)的問(wèn)題。但不是你的問(wèn)題。不停地問(wèn)自己,哪種情況更糟糕?一種情況是我們變成了一個(gè)龐大的,糟糕的軟件公司,充斥著許多腦袋空空如可可果殼的家伙,另一種情況是我們是一個(gè)小而高品質(zhì)的公司。當(dāng)然,找到優(yōu)秀的應(yīng)聘者(并聘用他們)是很重要的。找到有頭腦而且完成工作的人是公司中的每個(gè)員工的日常工作之一。但是當(dāng)你作為Joel Creek公司的一員真的開(kāi)始面試一個(gè)應(yīng)聘者時(shí),要裝作現(xiàn)在正有很多優(yōu)秀的人想打破頭擠進(jìn)Fog Creek公司??傊?,無(wú)論找到一個(gè)不錯(cuò)的應(yīng)聘者是多么的難,永遠(yuǎn)不要降低你的標(biāo)準(zhǔn)。

          但是你如何作出雇傭或者不雇傭這樣艱難的決定?你只要在面試過(guò)程中不停地問(wèn)自己:這個(gè)人有頭腦嗎?這個(gè)人能完成工作嗎?要作出正確的回答,在面試時(shí)你必須問(wèn)對(duì)問(wèn)題。

          開(kāi)個(gè)玩笑,下面我要問(wèn)個(gè)有史以來(lái)最差的面試問(wèn)題: “Oracle 8i中的數(shù)據(jù)類型varchar和varchar2有什么區(qū)別”這是一個(gè)可怕的問(wèn)題。掌握這種瑣碎的技術(shù)細(xì)節(jié)和Fog Creek公司想雇傭你之間沒(méi)有任何聯(lián)系。誰(shuí)會(huì)去記這種東西?如果有在線幫助,你可以在15秒內(nèi)找到答案。

          實(shí)際上,還有更差的問(wèn)題,等會(huì)兒我會(huì)談到的。

          現(xiàn)在我們要談到有趣的部分了:面試時(shí)提哪些問(wèn)題。我的面試問(wèn)題清單來(lái)自于我去微軟公司找第一份工作的經(jīng)歷。這里實(shí)際上有幾百個(gè)微軟面試問(wèn)題。每個(gè)人都有偏愛(ài)的問(wèn)題。你也可以發(fā)展一套自己的面試問(wèn)題以及面試的個(gè)人風(fēng)格,這樣你就可以比較容易地作出雇傭/不雇傭的決定。以下是我成功使用過(guò)的一些面試技巧,

          在面試前,我讀一遍應(yīng)試者的簡(jiǎn)歷,然后在一張紙片上隨便寫(xiě)以下我的面試計(jì)劃。這個(gè)計(jì)劃實(shí)際上就是我要問(wèn)的問(wèn)題清單。以下是一個(gè)例子(用來(lái)面試程序員的):

            1. 介紹
            2. 應(yīng)試者參加過(guò)的項(xiàng)目
            3. 無(wú)法回答的問(wèn)題
            4. C語(yǔ)言函數(shù)
            5. 你滿意嗎?
            6. 設(shè)計(jì)問(wèn)題
            7. 挑戰(zhàn)
            8. 你還有什么問(wèn)題?

          在面試前,我非常,非常當(dāng)心,避免自己先入為主。如果在面試前你就已經(jīng)想當(dāng)然地認(rèn)為,一個(gè)麻省理工的博士一定是一個(gè)有頭腦的人。那么在接下來(lái)的一小時(shí)的面試時(shí)間內(nèi),無(wú)論那個(gè)麻省理工的博士說(shuō)什么都不能改變你的最初印象。如果在面試前你就認(rèn)為這個(gè)應(yīng)試者是個(gè)傻瓜,那么他面試時(shí)說(shuō)什么也無(wú)濟(jì)于事。面試就象一個(gè)非常精巧的天平。一小時(shí)的面試結(jié)束后就要對(duì)一個(gè)人下結(jié)論是不容易的(但是你又必須在面試結(jié)束后得出結(jié)論)。一些不起眼的細(xì)節(jié)可能會(huì)影響最后的結(jié)論。如果你在面試開(kāi)始前對(duì)于應(yīng)試者有了一點(diǎn)了解的話,就好比天平的某一端加上了重重的砝碼。這樣面試本身就會(huì)變得沒(méi)有用處了。以前有一次在面試前,一個(gè)招聘負(fù)責(zé)人跑進(jìn)我的房間說(shuō),“你肯定會(huì)愛(ài)上這個(gè)家伙的!" 對(duì)一個(gè)男孩? 天哪,這簡(jiǎn)直讓我發(fā)瘋。我本來(lái)應(yīng)該說(shuō),“嗯,如果你這么確定我會(huì)喜歡他,為什么你不干脆雇傭他,何必讓我浪費(fèi)時(shí)間來(lái)面試?”但是那時(shí)我還太年輕幼稚, 所以還是面試了那個(gè)人。當(dāng)這個(gè)家伙開(kāi)始說(shuō)一些蠢話時(shí),我對(duì)自己說(shuō),“哇塞,這應(yīng)該是個(gè)例外情況,也許是大智若愚。”我開(kāi)始帶著玫瑰色眼鏡看他了。于是我以說(shuō)“雇傭”結(jié)束了面試,雖然他是一個(gè)糟糕的面試者。接下來(lái)發(fā)生了什么事?除了我,其他的面試官都說(shuō),不要雇傭這個(gè)人。教訓(xùn)是,不要聽(tīng)別的人的話,在面試應(yīng)試者前不要四處打探這個(gè)面試者的情況。最重要的是不要和別的面考官談?wù)搼?yīng)試者,除非你們都已經(jīng)作出了獨(dú)立的判斷。這才是科學(xué)的做法。

          作為面試步驟的第一步,介紹的目的是讓?xiě)?yīng)試者放輕松。我通常花30秒鐘,講一下我是誰(shuí),接下來(lái)面試會(huì)如何進(jìn)行。我總是使得應(yīng)試者確信,我們關(guān)心的是他(她)如何解決問(wèn)題的,而不是他(她)的最終答案是對(duì)還是錯(cuò)。順便說(shuō)一下,面試時(shí),你不要和應(yīng)試者隔著一個(gè)桌子坐著,否則在你和面試者之間就有了一個(gè)障礙,并且暗示著一種比較正式嚴(yán)肅的氣氛,這樣應(yīng)試者就很難放松了。更好的辦法是把桌子靠墻放著,或者和應(yīng)試者坐在桌子的同一邊,這樣有助于應(yīng)試者放松。只有應(yīng)試者不會(huì)因?yàn)榫o張而表現(xiàn)失常,你才能更有效的進(jìn)行面試.

          第二步的內(nèi)容就是問(wèn)應(yīng)試者最近做了些什么項(xiàng)目。對(duì)剛畢業(yè)的學(xué)生, 如果有論文就問(wèn)問(wèn)論文, 沒(méi)有的話, 就問(wèn)問(wèn)他們做過(guò)什么很喜歡的大作業(yè).例如,有時(shí)候我會(huì)問(wèn)一下,“你最喜歡上學(xué)期哪門(mén)課程?不一定要和計(jì)算機(jī)相關(guān)的。”事實(shí)上,如果應(yīng)試者回答的課程和計(jì)算機(jī)沒(méi)有關(guān)系,我會(huì)比較高興。有時(shí)候你會(huì)發(fā)現(xiàn)這個(gè)計(jì)算機(jī)系應(yīng)屆生選擇了盡可能少的計(jì)算機(jī)相關(guān)課程,但是卻選修了很多和音樂(lè)相關(guān)的課程。但是他(她)卻說(shuō)最喜歡的課程是《面向?qū)ο髷?shù)據(jù)庫(kù)》。哼哼,不錯(cuò)啊. 不過(guò)如果你直接承認(rèn)你喜歡音樂(lè)勝于計(jì)算機(jī), 而不是在這兒胡說(shuō)八道的話, 我會(huì)更高興一點(diǎn)。

          當(dāng)面試有工作經(jīng)驗(yàn)的人時(shí),你可以讓他們談一下前一份工作。

          我問(wèn)這個(gè)問(wèn)題的目的是在尋找一樣品質(zhì):熱情。在應(yīng)試者談到他(她)最近做過(guò)的項(xiàng)目時(shí),你觀察到以下跡象都是不錯(cuò)的:

          • 談到他們做過(guò)的項(xiàng)目時(shí)變得熱情洋溢;他們的語(yǔ)速更快,語(yǔ)言更生動(dòng)活潑。這說(shuō)明他們對(duì)某些東西有興趣,有熱情(因?yàn)楝F(xiàn)實(shí)中有許多人對(duì)所做的項(xiàng)目根本漠不關(guān)心呢)。即使他們激動(dòng)地表達(dá)對(duì)做過(guò)的項(xiàng)目的負(fù)面感情,這也是一個(gè)好的信號(hào)。“我曾經(jīng)為上一個(gè)老板安裝Foo Bar Mark II,但他是個(gè)傻瓜!”表現(xiàn)出熱情的人就是我們要雇傭的人。差的應(yīng)試者對(duì)工作根本就不關(guān)心,所以根本不會(huì)激動(dòng)。一個(gè)非常好的信號(hào)是當(dāng)應(yīng)試者很激動(dòng)地談?wù)撋弦环莨ぷ鳎灾劣跁簳r(shí)忘記了他們正在被面試。有時(shí)候應(yīng)試者剛開(kāi)始面試時(shí)表現(xiàn)的很緊張 -- 這是很正常的現(xiàn)象,所以我通常忽略不計(jì)。但是當(dāng)他們談到單色計(jì)算藝術(shù)(Computational Monochromatic Art)時(shí),這個(gè)家伙變得極端興奮, 一點(diǎn)都不緊張了。不錯(cuò),我喜歡這樣的應(yīng)試者,因?yàn)樗麄冴P(guān)心他們做的事。(什么是單色計(jì)算藝術(shù)?拔掉你的電腦顯示器的電源就可以看到了)
          • 能認(rèn)真地去解釋事情。某些人被我拒掉的原因就是他們不會(huì)用普通人能明白的語(yǔ)言去解釋他們做過(guò)的項(xiàng)目。很多工科專業(yè)的人總是以為所有人都知道Bates理論(譯者注: Bates Theorem,一種經(jīng)濟(jì)學(xué)的理論)或者Peano公理組(譯者注: Peano's Axioms,數(shù)論中的一些定理)是什么。如果應(yīng)試者開(kāi)始滿口行話了,讓他們停一停,然后你說(shuō),“能幫我個(gè)忙嗎?就是為了練習(xí)一下,你能把剛才說(shuō)的用我老祖母也能理解的話說(shuō)一遍嗎?”但即便如此, 有些人還是繼續(xù)用那些術(shù)語(yǔ), 而且根本沒(méi)法讓人明白他們?cè)谡f(shuō)什么。天哪!
          • 如果這個(gè)項(xiàng)目是一個(gè)團(tuán)隊(duì)項(xiàng)目,看看他們是否在有承擔(dān)領(lǐng)導(dǎo)責(zé)任的跡象?一個(gè)應(yīng)試者可能會(huì)說(shuō):“我們用的是X方法,但是老板說(shuō)應(yīng)該是Y,而客戶說(shuō)應(yīng)該是Z。”我會(huì)問(wèn),“那么怎么做的?”一個(gè)好的回答可能是“我設(shè)法和團(tuán)隊(duì)中別的人開(kāi)了個(gè)會(huì),然后一起搞出個(gè)辦法...”壞的回答看起來(lái)象,“嗯,我什么也不能做。這樣的問(wèn)題我解決不了。”記住,聰明并且能完成工作。要搞清楚某人是否能完成工作的一個(gè)辦法就是看看他(她)過(guò)去是否傾向于完成任務(wù)。事實(shí)上,你可以主動(dòng)要求他們給你個(gè)例子證明他們能擔(dān)任領(lǐng)導(dǎo)作用,完成任務(wù)。-例如克服公司的陳規(guī)陋習(xí)。

          現(xiàn)在我們談?wù)勄鍐紊系牡谌睿?em>無(wú)法回答的問(wèn)題。這很有趣。這個(gè)主意的關(guān)鍵在于問(wèn)一些不可能有答案的問(wèn)題,就是想看一下應(yīng)試者怎么辦。“西雅圖有多少眼科醫(yī)生?”“華盛頓紀(jì)念碑有多重?”“洛杉機(jī)有多少加油站?”“紐約有多少鋼琴調(diào)音師?”

          • 聰明的應(yīng)試者猜到你不是要測(cè)驗(yàn)他們的專業(yè)知識(shí),他們會(huì)積極地給出一個(gè)估計(jì)。“嗯,洛杉機(jī)的人口是七百萬(wàn);每個(gè)人平均擁有2.5輛轎車(chē)...”當(dāng)然如果他們的估計(jì)完全錯(cuò)誤了也沒(méi)有關(guān)系。重要的是他們能積極地試著回答問(wèn)題。他們可能會(huì)試著搞清楚每個(gè)加油站的儲(chǔ)量。“嗯,需要四分鐘給一個(gè)儲(chǔ)油罐加滿油,一個(gè)加油站有十個(gè)油泵每天運(yùn)行十八個(gè)小時(shí)...”他們也可能試著從占地面積來(lái)估計(jì)。有時(shí), 他們的想法的創(chuàng)造力讓你吃驚. 而有時(shí), 他們直接要一個(gè)LA的黃頁(yè)去查。這都是好跡象。
          • 不聰明的應(yīng)試者則被難住了。他們目瞪口呆地望著你,好像你來(lái)自火星。你不得不提示:“嗯,如果你想建立一個(gè)象洛杉機(jī)那么大的城市,你需要建立多少個(gè)加油站?”你還可以提示他們:“加滿一個(gè)儲(chǔ)油罐要多長(zhǎng)時(shí)間?”不過(guò),這些榆木疙瘩腦袋還是只會(huì)坐在那里發(fā)呆,你得拖著他們往前走才行。這類人不會(huì)解決問(wèn)題,我們可不要這樣的人。

          關(guān)于編程問(wèn)題,我通常要求應(yīng)試者用C語(yǔ)言寫(xiě)一些小函數(shù)。以下是我通常會(huì)出的題目:

          1. 將一個(gè)字符串逆序
          2. 將一個(gè)鏈表(linked list)逆序
          3. 計(jì)算一個(gè)字節(jié)(byte)里有多少bit被置1
          4. 搜索給定的字節(jié)(byte)
          5. 在一個(gè)字符串中找到可能的最長(zhǎng)的子字符串,該字符串是由同一字符組成的
          6. 字符串轉(zhuǎn)換成整數(shù)
          7. 整數(shù)轉(zhuǎn)換成字符串(這個(gè)問(wèn)題很不錯(cuò),因?yàn)閼?yīng)試者要用到堆?;蛘遱trev函數(shù))

          注意,通常你不會(huì)希望他們寫(xiě)的代碼多于5行,因?yàn)槟銢](méi)有時(shí)間理解太長(zhǎng)的代碼。

          現(xiàn)在我們來(lái)詳細(xì)看一看其中幾個(gè)問(wèn)題: 第一個(gè)問(wèn)題: 逆序一個(gè)字符串。我這輩子還沒(méi)有見(jiàn)過(guò)那個(gè)面試者能把這題目一次做對(duì)。所有的應(yīng)試者都試圖動(dòng)態(tài)生成緩沖區(qū),然后將逆序的字符串輸出到該緩沖區(qū)中。問(wèn)題的關(guān)鍵在于,誰(shuí)負(fù)責(zé)分配這個(gè)緩沖區(qū)?誰(shuí)又負(fù)責(zé)釋放那個(gè)緩沖區(qū)?通過(guò)這個(gè)問(wèn)題,我發(fā)現(xiàn)了一個(gè)有趣的事實(shí),就是大多數(shù)認(rèn)為自己懂C的人實(shí)際上不理解指針和內(nèi)存的概念。他們就是不明白。這真叫人吃驚,無(wú)法想象這種人也能做程序員。但他們真的就是!這個(gè)問(wèn)題可以從多個(gè)角度判斷應(yīng)試者:

          • 他們的函數(shù)運(yùn)行快嗎?看一下他們多少此調(diào)用了strlen函數(shù)。我曾經(jīng)看到應(yīng)試者寫(xiě)的strrev的算法竟然只有O(n^2) 的效率,而標(biāo)準(zhǔn)的算法效率應(yīng)該是O(n),效率如此底下的原因是因?yàn)樗麄冊(cè)谘h(huán)中一次又一次調(diào)用strlen函數(shù)。
          • 他們使用指針運(yùn)算嗎(譯者按:原文為pointer arithmetic,指的是加減指針變量的值)?使用指針運(yùn)算是個(gè)好現(xiàn)象。許多所謂的“C程序員”竟然不知道如何使用指針運(yùn)算(pointer arithmetic)。當(dāng)然,我在前文說(shuō)過(guò)我不會(huì)因?yàn)閼?yīng)試者不掌握一種特定的技巧而拒絕他。但是,理解C語(yǔ)言中的指針不是一種技巧,而是一種與生俱來(lái)的才能。每年一所大學(xué)要招進(jìn)200多個(gè)計(jì)算機(jī)系的新生,所有這些小孩子4歲就開(kāi)始用BASIC語(yǔ)言在Atari 800s寫(xiě)冒險(xiǎn)游戲了。在大學(xué)里他們還學(xué)Pascal語(yǔ)言,學(xué)得也很棒。直到有一天他們的教授講了指針的概念,突然,他們開(kāi)始搞不懂了。他們就是不能再理解C語(yǔ)言中的任何東西了。于是90%的計(jì)算機(jī)系學(xué)生轉(zhuǎn)系去學(xué)政治學(xué)。為了挽回面子,他們告訴朋友,他們之所以轉(zhuǎn)系是因?yàn)樗麄冇?jì)算機(jī)系英俊貌美的異性太少。許多人注定腦子里就沒(méi)有理解指針的那根弦。所以說(shuō)理解指針是一種與生俱來(lái)的品質(zhì),而不是一種單純的技巧。理解指針需要腦子轉(zhuǎn)好幾個(gè)彎,某些人天生不擅長(zhǎng)轉(zhuǎn)這幾個(gè)彎。

          第三個(gè)問(wèn)題可以考考面試者對(duì)C的位運(yùn)算的掌握,但這是一種技巧,不是一種品質(zhì),所以你可以幫助他們。有趣的等他們建立了一個(gè)子函數(shù)用來(lái)計(jì)算byte中為1的位的數(shù)目,然后你要求他們優(yōu)化這個(gè)子函數(shù),盡量加快這個(gè)函數(shù)的運(yùn)行速度。聰明的應(yīng)試者會(huì)使用查表算法(畢竟這個(gè)表只有 256個(gè)元素,用不了多少內(nèi)存),整個(gè)表只需要建立一次。跟聰明的應(yīng)試者討論一下提高時(shí)間/空間效率的不同策略是十分有意思的事情. 進(jìn)一步告訴他們你不想在程序啟動(dòng)時(shí)初始化查詢表。聰明的面試者可能會(huì)建議使用緩沖機(jī)制,對(duì)于一個(gè)特定的byte,只有在第一次被查詢時(shí)進(jìn)行計(jì)算,然后計(jì)算結(jié)果會(huì)被放入查詢表。這樣以后再被查詢時(shí)直接查表就行了。而特別特別聰明的面試這會(huì)嘗試有沒(méi)有建立查詢表的捷徑,如一個(gè)byte和它的置1的bit數(shù)之間有沒(méi)有規(guī)律可循? 

          當(dāng)你觀察應(yīng)試者寫(xiě)C代碼時(shí),以下一些技巧會(huì)對(duì)你有幫助:

          • 事先向應(yīng)試者說(shuō)明,你完全理解,沒(méi)有一個(gè)好的編輯器光在紙上寫(xiě)代碼是困難的,所以你不在乎他們手寫(xiě)的代碼是否看上去不整潔。你也完全明白沒(méi)有好的編譯器和調(diào)試器,很難第一次就寫(xiě)出完全沒(méi)有bug的程序,所以請(qǐng)他們不必為此擔(dān)心。
          • 好程序員的標(biāo)志:好程序員寫(xiě)完“{”符號(hào)后,通常立刻跟上“}”符號(hào),然后再在當(dāng)中填上代碼。他們也傾向于使用命名規(guī)則,雖然這個(gè)規(guī)則可能很原始。如果一個(gè)變量用作循環(huán)語(yǔ)句的索引,好程序員通常使用盡可能少的字符為它命名。如果他們的循環(huán)語(yǔ)句的索引變量的名字是CurrentPagePositionLoopCounter,顯而易見(jiàn)他們寫(xiě)代碼的經(jīng)驗(yàn)還不夠多。偶爾,你會(huì)看到一個(gè)C程序員寫(xiě)下象if (0==strlen(x))一樣的代碼,常量被放在==的左邊。這是非常好的現(xiàn)象。這說(shuō)明他因?yàn)榭偸前眩胶停剑礁慊?,已?jīng)強(qiáng)迫自己養(yǎng)成這種習(xí)慣以避免犯錯(cuò)。
          • 好的程序員在寫(xiě)代碼前會(huì)訂一個(gè)計(jì)劃,特別是當(dāng)他們的代碼用到了指針時(shí)。例如,如果你要求逆序一個(gè)鏈表,好程序員通常會(huì)在紙的一邊畫(huà)上鏈表的草圖,并表明算法中的索引指針當(dāng)前移動(dòng)到的位置。他們不得不這樣做。正常人是不可能不借助草圖就開(kāi)始寫(xiě)一個(gè)逆序鏈表的程序的。差的程序員立刻開(kāi)始寫(xiě)代碼。

          不可避免的,你會(huì)在他們的程序中發(fā)現(xiàn)bug,于是我們現(xiàn)在來(lái)到了第五個(gè)問(wèn)題:你對(duì)代碼滿意嗎? 你可能想問(wèn),“好吧,bug在哪里?”這是來(lái)自地獄的一針見(jiàn)血的問(wèn)題,要回答這個(gè)問(wèn)題可要大費(fèi)口舌。所有的程序員都會(huì)犯錯(cuò)誤,這不是問(wèn)題。但他們必須能找到錯(cuò)誤。對(duì)于字符串操作的函數(shù),他們通常會(huì)忘記在輸出緩沖區(qū)加上字符串結(jié)束符。所有的函數(shù),他們都會(huì)犯off-by-one錯(cuò)誤(譯者按:指的是某個(gè)變量的最大值和最小值可能會(huì)和正常值差1)。他們會(huì)忘掉正常的C語(yǔ)句結(jié)尾的分號(hào)。如果輸入是零長(zhǎng)度字符串,他們的函數(shù)會(huì)運(yùn)行錯(cuò)誤。如果malloc調(diào)用失敗而他們沒(méi)有為此寫(xiě)好錯(cuò)誤處理代碼,程序會(huì)崩潰。一次就能把所有事情做對(duì)的程序員非常,非常,非常地少.不過(guò)要是真的碰上一個(gè)的話, 提問(wèn)就更有意思了. 你說(shuō),"還有Bug"。他們會(huì)再仔細(xì)地檢查一遍代碼。這個(gè)時(shí)候, 觀察一下他們內(nèi)心是否開(kāi)始動(dòng)搖了, 只是表面上勉強(qiáng)堅(jiān)持說(shuō)代碼沒(méi)有問(wèn)題??傊?,在程序員寫(xiě)完代碼后,問(wèn)一下他們是否對(duì)代碼滿意是個(gè)好主意。就像Regis那樣問(wèn)他們!(譯者按,Regis Philbin是美國(guó)ABC電視網(wǎng)的游戲電視節(jié)目主持人,他的口頭禪是“這是你的最后的答案嗎?”)

          第六部分:關(guān)于設(shè)計(jì)的問(wèn)題。讓?xiě)?yīng)試者設(shè)計(jì)某樣?xùn)|西。Jabe Blumenthal,Excel的原始設(shè)計(jì)者,喜歡讓?xiě)?yīng)試者設(shè)計(jì)房子。Jabe說(shuō),曾經(jīng)有一個(gè)應(yīng)試者跑到白板前,畫(huà)了一個(gè)方塊,這就是他的全部設(shè)計(jì)。天哪,一個(gè)方塊!立刻拒絕這樣的家伙。你喜歡問(wèn)什么樣的設(shè)計(jì)問(wèn)題?

          • 好的程序員會(huì)問(wèn)更多的信息。房子為誰(shuí)造的?我們公司的政策是,我們不會(huì)雇傭那些在設(shè)計(jì)前不問(wèn)為誰(shuí)設(shè)計(jì)的人。通常,我會(huì)很煩惱我得打斷他們的設(shè)計(jì),說(shuō)“事實(shí)上,你忘記問(wèn)這個(gè)房子是給誰(shuí)設(shè)計(jì)的了。這個(gè)房子是給一群長(zhǎng)頸鹿造的。”
          • 笨笨的應(yīng)試者認(rèn)為設(shè)計(jì)就像畫(huà)畫(huà),你想畫(huà)什么就畫(huà)什么。聰明的應(yīng)試者明白設(shè)計(jì)的過(guò)程是一系列艱難的權(quán)衡。一個(gè)很棒的設(shè)計(jì)問(wèn)題是:設(shè)計(jì)一個(gè)放在街角的垃圾箱。想一想你得做多少權(quán)衡!垃圾箱必須易于清空,但是很難被偷走;易于放進(jìn)垃圾,但是碰到狂風(fēng)大作,里面的垃圾不會(huì)被吹出來(lái);垃圾箱必須堅(jiān)固而便宜。在某些城市,垃圾箱必須特別設(shè)計(jì),以防恐怖分子在里面藏一個(gè)定時(shí)炸彈。
          • 有創(chuàng)造力的應(yīng)試者會(huì)給出有趣而獨(dú)特的設(shè)計(jì)。我最喜歡的問(wèn)題之一是為盲人設(shè)計(jì)一個(gè)放調(diào)味品的架子(譯者按:原文為spice rack,老外的廚房里有個(gè)專門(mén)放調(diào)味品的架子,上面放了很多小罐罐,里面裝了各種各樣的調(diào)料)通常許多應(yīng)試者的建議是把布萊葉文(一種盲人使用的文字)刻在放調(diào)料的罐子上,這樣文字會(huì)卷起來(lái)而變形。我碰到一個(gè)應(yīng)試者,他的設(shè)計(jì)是把調(diào)料放在抽屜里,因?yàn)樗X(jué)得水平地感知布萊葉文比垂直地做更方便。(試試看?。┻@個(gè)答案這樣有創(chuàng)意,使我震驚!我面試了有一打得程序員,從來(lái)沒(méi)有人想到過(guò)類似的答案。這樣有創(chuàng)意的答案確實(shí)躍過(guò)了普通人考慮問(wèn)題的條條框框。僅僅因?yàn)檫@個(gè)答案太有創(chuàng)意了,而且應(yīng)試者別的方面還過(guò)得去,我雇傭了這個(gè)應(yīng)試者,他現(xiàn)在已經(jīng)成為Excel團(tuán)隊(duì)中一個(gè)優(yōu)秀的項(xiàng)目經(jīng)理了(譯者按,本文作者曾在微軟工作過(guò))。
          • 總是爭(zhēng)取一個(gè)確定的了結(jié)。這也是完成工作的特質(zhì)的一部分。有時(shí)候應(yīng)試者會(huì)猶猶豫豫不能作出一個(gè)決定,試圖回避困難的問(wèn)題,留著困難的問(wèn)題不作決定就直接向下進(jìn)行,這很不好。好的應(yīng)試者有一種推動(dòng)事情自然地前進(jìn)的傾向,即使你有意把他們拖回來(lái)。如果關(guān)于某個(gè)話題的討論開(kāi)始原地打轉(zhuǎn)變得沒(méi)有意義了,好的應(yīng)試者會(huì)說(shuō),“嗯,我們可以整天談?wù)撨@個(gè),但是我們得做點(diǎn)什么。為什么我們不開(kāi)始...”

          于是我們來(lái)到了第七部分,挑戰(zhàn)。這部分很好玩。在面試中留心一下, 當(dāng)面試者的回答絕對(duì)的百分之百毫無(wú)爭(zhēng)議時(shí), 你可以說(shuō): " 嗯, 等一下等一下." 然后花上兩分鐘玩一下魔鬼的游戲(譯者按,原文為devil's advocate,魔鬼代言人指的是違背自己的良知,為錯(cuò)誤邪惡的觀點(diǎn)辯護(hù)). 記住一定要在你可以肯定他正確時(shí)和他爭(zhēng)論。

          這個(gè)很有意思.  
          • 軟弱的應(yīng)試者會(huì)屈服。那我就和他說(shuō)拜拜了。
          • 堅(jiān)定的應(yīng)試者會(huì)找到一個(gè)辦法說(shuō)服你。他們會(huì)以肯尼迪總統(tǒng)的口才來(lái)說(shuō)服你,“也許我誤會(huì)了你的意思,”他們這樣開(kāi)頭,但是正文仍是堅(jiān)定地站穩(wěn)立場(chǎng)。這樣的人我就雇傭

          不得不承認(rèn),面試雙方的地位并不是平等的。有可能應(yīng)試者由于害怕你的權(quán)力而不敢于你爭(zhēng)辯。但是,好的應(yīng)試者有足夠的熱情和勇氣堅(jiān)持正確的觀點(diǎn),他們由于熱切希望說(shuō)服你而會(huì)暫時(shí)忘記正在被面試。這樣的人就是我們要雇傭的人。

          最后,可以問(wèn)一下應(yīng)試者有什么想問(wèn)的。一些人喜歡看看應(yīng)試者這時(shí)是否會(huì)問(wèn)一些聰明的問(wèn)題。這是市面上流行的面試書(shū)籍的標(biāo)準(zhǔn)技巧。我個(gè)人不在乎應(yīng)試者問(wèn)什么,因?yàn)檫@時(shí)我已經(jīng)做了決定。麻煩在于,應(yīng)試者也許已經(jīng)見(jiàn)了5、6個(gè)人,進(jìn)行了好幾輪面試,他們可能很累了,以至于不能為每輪面試都準(zhǔn)備一個(gè)聰明而獨(dú)特的問(wèn)題。所以如果他們沒(méi)有可問(wèn)的,沒(méi)關(guān)系。

          我總是留下面試的最后5分鐘來(lái)推銷(xiāo)我的公司。這很重要。即使我不打算雇傭眼前這個(gè)應(yīng)試者。如果你幸運(yùn)的找到一個(gè)很棒的應(yīng)試者,你當(dāng)然愿意做任何事情說(shuō)服他(她)來(lái)你的公司。即使他們不是好的應(yīng)試者,你也要盡力讓他們?yōu)镕og Creek公司激動(dòng),這樣面試結(jié)束時(shí)他們會(huì)對(duì)Fog Creek公司留下一個(gè)很好的印象。記住,應(yīng)試者并不僅僅是可能的雇員,他們也是顧客,也是我們公司的推銷(xiāo)員。如果他們覺(jué)得我們的公司很棒,他們也許會(huì)推薦朋友來(lái)面試。

          啊哈,我記得我說(shuō)過(guò)我會(huì)給出一些應(yīng)該避免的非常不好的反面的試題例子。

          首先,避免不合法的問(wèn)題。有關(guān)種族,宗教,性別,出生國(guó),年齡,服役記錄,是否老兵,性取向,生理障礙的問(wèn)題都是不合法的。即使他們的簡(jiǎn)歷說(shuō)他們1990年在軍中服役,也不要問(wèn)有關(guān)問(wèn)題。也許這會(huì)讓他們愉快地談?wù)撛诤硲?zhàn)爭(zhēng)中的經(jīng)歷。但是你的問(wèn)題還是不合法的。如果簡(jiǎn)歷上寫(xiě)著他們上過(guò)Technion in Haifa, 不要問(wèn)他們是否是以色列人, 即使只是為了閑談, 因?yàn)檫@是違法的. 下面有一個(gè)很好的不合法的例子。點(diǎn)擊這里有很多關(guān)于什么是違法的討論。(但是這個(gè)網(wǎng)站的其余問(wèn)題夠愚蠢的。)

          其次,不要在問(wèn)題中給予應(yīng)試者暗示,我們公司喜歡或者不喜歡什么樣的員工。我能想到的一個(gè)例子是問(wèn)應(yīng)試者是否有小孩或者是否結(jié)婚了。應(yīng)試者也許會(huì)想我們不喜歡有家庭拖累的員工。

          最后,不要問(wèn)那些腦筋急轉(zhuǎn)彎的題目,例如6根火柴怎么拼出4個(gè)三角形。象這樣的靈機(jī)一動(dòng)的問(wèn)題是不能看出應(yīng)試者是否有“有頭腦/完成工作”的品質(zhì)。

          面試與其說(shuō)是科學(xué)不如說(shuō)是藝術(shù)。但是只要你記住有頭腦/完成工作這個(gè)原則,你就可以應(yīng)對(duì)自如。有機(jī)會(huì)就問(wèn)問(wèn)你的同事他們喜歡的面試問(wèn)題和答案。這是我們公司員工午飯時(shí)熱衷的話題之一。

          本文最先用英文出版,題為 The Guerrilla Guide to Interviewing

          作者簡(jiǎn)介   Joel Spolsky 是紐約市一家小軟件公司,Fog Creek Software, 的創(chuàng)始人。他畢業(yè)于耶魯大學(xué),曾在美國(guó)微軟公司,Viacom,  Juno 任軟件設(shè)計(jì)師及經(jīng)理。

           

           

          [顯示打印版本]

          相關(guān)文章

          • No Relative Articles.

          相關(guān)評(píng)論   發(fā)表評(píng)論

          • No Comments
          posted @ 2008-11-04 21:29 poower 閱讀(225) | 評(píng)論 (0)編輯 收藏

          想成為嵌入式程序員應(yīng)知道的0x10個(gè)基本問(wèn)題

          簡(jiǎn)述:

          這是嵌入式C程序員的基本知識(shí)。作者在Embedded Systems Programming雜志上發(fā)表了很多嵌入式系統(tǒng)開(kāi)發(fā)方面的文章。

          作者:Jones Nigel   更新日期:2005-04-08
          來(lái)源:internet   瀏覽次數(shù):

                  C語(yǔ)言測(cè)試是招聘嵌入式系統(tǒng)程序員過(guò)程中必須而且有效的方法。這些年,我既參加也組織了許多這種測(cè)試,在這過(guò)程中我意識(shí)到這些測(cè)試能為面試者和被面試者提供許多有用信息,此外,撇開(kāi)面試的壓力不談,這種測(cè)試也是相當(dāng)有趣的。
                  從被面試者的角度來(lái)講,你能了解許多關(guān)于出題者或監(jiān)考者的情況。這個(gè)測(cè)試只是出題者為顯示其對(duì)ANSI標(biāo)準(zhǔn)細(xì)節(jié)的知識(shí)而不是技術(shù)技巧而設(shè)計(jì)嗎?這是個(gè)愚蠢的問(wèn)題嗎?如要你答出某個(gè)字符的ASCII值。這些問(wèn)題著重考察你的系統(tǒng)調(diào)用和內(nèi)存分配策略方面的能力嗎?這標(biāo)志著出題者也許花時(shí)間在微機(jī)上而不是在嵌入式系統(tǒng)上。如果上述任何問(wèn)題的答案是"是"的話,那么我知道我得認(rèn)真考慮我是否應(yīng)該去做這份工作。
                  從面試者的角度來(lái)講,一個(gè)測(cè)試也許能從多方面揭示應(yīng)試者的素質(zhì):最基本的,你能了解應(yīng)試者C語(yǔ)言的水平。不管怎么樣,看一下這人如何回答他不會(huì)的問(wèn)題也是滿有趣。應(yīng)試者是以好的直覺(jué)做出明智的選擇,還是只是瞎蒙呢?當(dāng)應(yīng)試者在某個(gè)問(wèn)題上卡住時(shí)是找借口呢,還是表現(xiàn)出對(duì)問(wèn)題的真正的好奇心,把這看成學(xué)習(xí)的機(jī)會(huì)呢?我發(fā)現(xiàn)這些信息與他們的測(cè)試成績(jī)一樣有用。
                  有了這些想法,我決定出一些真正針對(duì)嵌入式系統(tǒng)的考題,希望這些令人頭痛的考題能給正在找工作的人一點(diǎn)幫助。這些問(wèn)題都是我這些年實(shí)際碰到的。其中有些題很難,但它們應(yīng)該都能給你一點(diǎn)啟迪。
                  這個(gè)測(cè)試適于不同水平的應(yīng)試者,大多數(shù)初級(jí)水平的應(yīng)試者的成績(jī)會(huì)很差,經(jīng)驗(yàn)豐富的程序員應(yīng)該有很好的成績(jī)。為了讓你能自己決定某些問(wèn)題的偏好,每個(gè)問(wèn)題沒(méi)有分配分?jǐn)?shù),如果選擇這些考題為你所用,請(qǐng)自行按你的意思分配分?jǐn)?shù)。

          預(yù)處理器(Preprocessor)

          1 . 用預(yù)處理指令#define 聲明一個(gè)常數(shù),用以表明1年中有多少秒(忽略閏年問(wèn)題)
                   #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
          我在這想看到幾件事情:
          1) #define 語(yǔ)法的基本知識(shí)(例如:不能以分號(hào)結(jié)束,括號(hào)的使用,等等)
          2)懂得預(yù)處理器將為你計(jì)算常數(shù)表達(dá)式的值,因此,直接寫(xiě)出你是如何計(jì)算一年中有多少秒而不是計(jì)算出實(shí)際的值,是更清晰而沒(méi)有代價(jià)的。
          3) 意識(shí)到這個(gè)表達(dá)式將使一個(gè)16位機(jī)的整型數(shù)溢出-因此要用到長(zhǎng)整型符號(hào)L,告訴編譯器這個(gè)常數(shù)是的長(zhǎng)整型數(shù)。
          4) 如果你在你的表達(dá)式中用到UL(表示無(wú)符號(hào)長(zhǎng)整型),那么你有了一個(gè)好的起點(diǎn)。記住,第一印象很重要。

          2 . 寫(xiě)一個(gè)"標(biāo)準(zhǔn)"宏MIN ,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)。
                  #define MIN(A,B) ((A) <= (B) ? (A) : (B))
          這個(gè)測(cè)試是為下面的目的而設(shè)的:
          1) 標(biāo)識(shí)#define在宏中應(yīng)用的基本知識(shí)。這是很重要的。因?yàn)樵?nbsp; 嵌入(inline)操作符 變?yōu)闃?biāo)準(zhǔn)C的一部分之前,宏是方便產(chǎn)生嵌入代碼的唯一方法,對(duì)于嵌入式系統(tǒng)來(lái)說(shuō),為了能達(dá)到要求的性能,嵌入代碼經(jīng)常是必須的方法。
          2)三重條件操作符的知識(shí)。這個(gè)操作符存在C語(yǔ)言中的原因是它使得編譯器能產(chǎn)生比if-then-else更優(yōu)化的代碼,了解這個(gè)用法是很重要的。
          3) 懂得在宏中小心地把參數(shù)用括號(hào)括起來(lái)
          4) 我也用這個(gè)問(wèn)題開(kāi)始討論宏的副作用,例如:當(dāng)你寫(xiě)下面的代碼時(shí)會(huì)發(fā)生什么事?
                  least = MIN(*p++, b);

          3. 預(yù)處理器標(biāo)識(shí)#error的目的是什么?
          如果你不知道答案,請(qǐng)看參考文獻(xiàn)1。這問(wèn)題對(duì)區(qū)分一個(gè)正常的伙計(jì)和一個(gè)書(shū)呆子是很有用的。只有書(shū)呆子才會(huì)讀C語(yǔ)言課本的附錄去找出象這種問(wèn)題的答案。當(dāng)然如果你不是在找一個(gè)書(shū)呆子,那么應(yīng)試者最好希望自己不要知道答案。


          死循環(huán)(Infinite loops)

          4. 嵌入式系統(tǒng)中經(jīng)常要用到無(wú)限循環(huán),你怎么樣用C編寫(xiě)死循環(huán)呢?
          這個(gè)問(wèn)題用幾個(gè)解決方案。我首選的方案是:

          while(1)
          {

          }

          一些程序員更喜歡如下方案:

          for(;;)
          {

          }

          這個(gè)實(shí)現(xiàn)方式讓我為難,因?yàn)檫@個(gè)語(yǔ)法沒(méi)有確切表達(dá)到底怎么回事。如果一個(gè)應(yīng)試者給出這個(gè)作為方案,我將用這個(gè)作為一個(gè)機(jī)會(huì)去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教著這樣做,但從沒(méi)有想到過(guò)為什么。"這會(huì)給我留下一個(gè)壞印象。

          第三個(gè)方案是用 goto
          Loop:
          ...
          goto Loop;
          應(yīng)試者如給出上面的方案,這說(shuō)明或者他是一個(gè)匯編語(yǔ)言程序員(這也許是好事)或者他是一個(gè)想進(jìn)入新領(lǐng)域的BASIC/FORTRAN程序員。


          數(shù)據(jù)聲明(Data declarations)

          5. 用變量a給出下面的定義
          a) 一個(gè)整型數(shù)(An integer)
          b)一個(gè)指向整型數(shù)的指針( A pointer to an integer)
          c)一個(gè)指向指針的的指針,它指向的指針是指向一個(gè)整型數(shù)( A pointer to a pointer to an intege)r
          d)一個(gè)有10個(gè)整型數(shù)的數(shù)組( An array of 10 integers)
          e) 一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的。(An array of 10 pointers to integers)
          f) 一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針( A pointer to an array of 10 integers)
          g) 一個(gè)指向函數(shù)的指針,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)(A pointer to a function that takes an integer as an argument and returns an integer)
          h) 一個(gè)有10個(gè)指針的數(shù)組,該指針指向一個(gè)函數(shù),該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)( An array of ten pointers to functions that take an integer argument and return an integer )

          答案是:
          a) int a; // An integer
          b) int *a; // A pointer to an integer
          c) int **a; // A pointer to a pointer to an integer
          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 10 integers
          g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
          h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

          人們經(jīng)常聲稱這里有幾個(gè)問(wèn)題是那種要翻一下書(shū)才能回答的問(wèn)題,我同意這種說(shuō)法。當(dāng)我寫(xiě)這篇文章時(shí),為了確定語(yǔ)法的正確性,我的確查了一下書(shū)。但是當(dāng)我被面試的時(shí)候,我期望被問(wèn)到這個(gè)問(wèn)題(或者相近的問(wèn)題)。因?yàn)樵诒幻嬖嚨倪@段時(shí)間里,我確定我知道這個(gè)問(wèn)題的答案。應(yīng)試者如果不知道所有的答案(或至少大部分答案),那么也就沒(méi)有為這次面試做準(zhǔn)備,如果該面試者沒(méi)有為這次面試做準(zhǔn)備,那么他又能為什么出準(zhǔn)備呢?

          Static

          6. 關(guān)鍵字static的作用是什么?
          這個(gè)簡(jiǎn)單的問(wèn)題很少有人能回答完全。在C語(yǔ)言中,關(guān)鍵字static有三個(gè)明顯的作用:
          1)在函數(shù)體,一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過(guò)程中維持其值不變。
          2) 在模塊內(nèi)(但在函數(shù)體外),一個(gè)被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外其它函數(shù)訪問(wèn)。它是一個(gè)本地的全局變量。
          3) 在模塊內(nèi),一個(gè)被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。

          大多數(shù)應(yīng)試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個(gè)應(yīng)試者的嚴(yán)重的缺點(diǎn),因?yàn)樗@然不懂得本地化數(shù)據(jù)和代碼范圍的好處和重要性。


          Const

          7.關(guān)鍵字const有什么含意?
          我只要一聽(tīng)到被面試者說(shuō):"const意味著常數(shù)",我就知道我正在和一個(gè)業(yè)余者打交道。去年Dan Saks已經(jīng)在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應(yīng)該非常熟悉const能做什么和不能做什么.如果你從沒(méi)有讀到那篇文章,只要能說(shuō)出const意味著"只讀"就可以了。盡管這個(gè)答案不是完全的答案,但我接受它作為一個(gè)正確的答案。(如果你想知道更詳細(xì)的答案,仔細(xì)讀一下Saks的文章吧。)
          如果應(yīng)試者能正確回答這個(gè)問(wèn)題,我將問(wèn)他一個(gè)附加的問(wèn)題:
          下面的聲明都是什么意思?

          const int a;
          int const a;
          const int *a;
          int * const a;
          int const * a const;

          /******/
          前兩個(gè)的作用是一樣,a是一個(gè)常整型數(shù)。第三個(gè)意味著a是一個(gè)指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)。第四個(gè)意思a是一個(gè)指向整型數(shù)的常指針(也就是說(shuō),指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。最后一個(gè)意味著a是一個(gè)指向常整型數(shù)的常指針(也就是說(shuō),指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不可修改的)。如果應(yīng)試者能正確回答這些問(wèn)題,那么他就給我留下了一個(gè)好印象。順帶提一句,也許你可能會(huì)問(wèn),即使不用關(guān)鍵字 const,也還是能很容易寫(xiě)出功能正確的程序,那么我為什么還要如此看重關(guān)鍵字const呢?我也如下的幾下理由:
          1) 關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息,實(shí)際上,聲明一個(gè)參數(shù)為常量是為了告訴了用戶這個(gè)參數(shù)的應(yīng)用目的。如果你曾花很多時(shí)間清理其它人留下的垃圾,你就會(huì)很快學(xué)會(huì)感謝這點(diǎn)多余的信息。(當(dāng)然,懂得用const的程序員很少會(huì)留下的垃圾讓別人來(lái)清理的。)
          2) 通過(guò)給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。
          3) 合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù),防止其被無(wú)意的代碼修改。簡(jiǎn)而言之,這樣可以減少bug的出現(xiàn)。


          Volatile

          8. 關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子。
          一個(gè)定義為volatile的變量是說(shuō)這變量可能會(huì)被意想不到地改變,這樣,編譯器就不會(huì)去假設(shè)這個(gè)變量的值了。精確地說(shuō)就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個(gè)例子:
          1) 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
          2) 一個(gè)中斷服務(wù)子程序中會(huì)訪問(wèn)到的非自動(dòng)變量(Non-automatic variables)
          3) 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量

          回答不出這個(gè)問(wèn)題的人是不會(huì)被雇傭的。我認(rèn)為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最基本的問(wèn)題。搞嵌入式的家伙們經(jīng)常同硬件、中斷、RTOS等等打交道,所有這些都要求用到volatile變量。不懂得volatile的內(nèi)容將會(huì)帶來(lái)災(zāi)難。
          假設(shè)被面試者正確地回答了這是問(wèn)題(嗯,懷疑是否會(huì)是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
          1)一個(gè)參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
          2); 一個(gè)指針可以是volatile 嗎?解釋為什么。
          3); 下面的函數(shù)有什么錯(cuò)誤:

          int square(volatile int *ptr)
          {
                  return *ptr * *ptr;
          }

          下面是答案:
          1)是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖?。它是const因?yàn)槌绦虿粦?yīng)該試圖去修改它。
          2); 是的。盡管這并不很常見(jiàn)。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer的指針時(shí)。
          3) 這段代碼有點(diǎn)變態(tài)。這段代碼的目的是用來(lái)返指針*ptr指向值的平方,但是,由于*ptr指向一個(gè)volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:

          int square(volatile int *ptr)
          {
              int a,b;
              a = *ptr;
              b = *ptr;
              return a * b;
          }

          由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:

          long square(volatile int *ptr)
          {
              int a;
              a = *ptr;
              return a * a;
          }

          位操作(Bit manipulation)

          9. 嵌入式系統(tǒng)總是要用戶對(duì)變量或寄存器進(jìn)行位操作。給定一個(gè)整型變量a,寫(xiě)兩段代碼,第一個(gè)設(shè)置a的bit 3,第二個(gè)清除a 的bit 3。在以上兩個(gè)操作中,要保持其它位不變。
          對(duì)這個(gè)問(wèn)題有三種基本的反應(yīng)
          1)不知道如何下手。該被面者從沒(méi)做過(guò)任何嵌入式系統(tǒng)的工作。
          2) 用bit fields。Bit fields是被扔到C語(yǔ)言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時(shí)也保證了的你的代碼是不可重用的。我最近不幸看到 Infineon為其較復(fù)雜的通信芯片寫(xiě)的驅(qū)動(dòng)程序,它用到了bit fields因此完全對(duì)我無(wú)用,因?yàn)槲业木幾g器用其它的方式來(lái)實(shí)現(xiàn)bit fields的。從道德講:永遠(yuǎn)不要讓一個(gè)非嵌入式的家伙粘實(shí)際硬件的邊。
          3) 用 #defines 和 bit masks 操作。這是一個(gè)有極高可移植性的方法,是應(yīng)該被用到的方法。最佳的解決方案如下:

          #define BIT3 (0x1 << 3)
          static int a;

          void set_bit3(void)
          {
              a |= BIT3;
          }
          void clear_bit3(void)
          {
              a &= ~BIT3;
          }

          一些人喜歡為設(shè)置和清除值而定義一個(gè)掩碼同時(shí)定義一些說(shuō)明常數(shù),這也是可以接受的。我希望看到幾個(gè)要點(diǎn):說(shuō)明常數(shù)、|=和&=~操作。


          訪問(wèn)固定的內(nèi)存位置(Accessing fixed memory locations)

          10. 嵌入式系統(tǒng)經(jīng)常具有要求程序員去訪問(wèn)某特定的內(nèi)存位置的特點(diǎn)。在某工程中,要求設(shè)置一絕對(duì)地址為0x67a9的整型變量的值為0xaa66。編譯器是一個(gè)純粹的ANSI編譯器。寫(xiě)代碼去完成這一任務(wù)。
          這一問(wèn)題測(cè)試你是否知道為了訪問(wèn)一絕對(duì)地址把一個(gè)整型數(shù)強(qiáng)制轉(zhuǎn)換(typecast)為一指針是合法的。這一問(wèn)題的實(shí)現(xiàn)方式隨著個(gè)人風(fēng)格不同而不同。典型的類似代碼如下:
              int *ptr;
              ptr = (int *)0x67a9;
              *ptr = 0xaa55;

           A more obscure approach is:
          一個(gè)較晦澀的方法是:

              *(int * const)(0x67a9) = 0xaa55;

          即使你的品味更接近第二種方案,但我建議你在面試時(shí)使用第一種方案。

          中斷(Interrupts)

          11. 中斷是嵌入式系統(tǒng)中重要的組成部分,這導(dǎo)致了很多編譯開(kāi)發(fā)商提供一種擴(kuò)展—讓標(biāo)準(zhǔn)C支持中斷。具代表事實(shí)是,產(chǎn)生了一個(gè)新的關(guān)鍵字 __interrupt。下面的代碼就使用了__interrupt關(guān)鍵字去定義了一個(gè)中斷服務(wù)子程序(ISR),請(qǐng)?jiān)u論一下這段代碼的。

          __interrupt double compute_area (double radius)
          {
              double area = PI * radius * radius;
              printf("\nArea = %f", area);
              return area;
          }

          這個(gè)函數(shù)有太多的錯(cuò)誤了,以至讓人不知從何說(shuō)起了:
          1)ISR 不能返回一個(gè)值。如果你不懂這個(gè),那么你不會(huì)被雇用的。
          2) ISR 不能傳遞參數(shù)。如果你沒(méi)有看到這一點(diǎn),你被雇用的機(jī)會(huì)等同第一項(xiàng)。
          3) 在許多的處理器/編譯器中,浮點(diǎn)一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點(diǎn)運(yùn)算。此外,ISR應(yīng)該是短而有效率的,在ISR中做浮點(diǎn)運(yùn)算是不明智的。
          4) 與第三點(diǎn)一脈相承,printf()經(jīng)常有重入和性能上的問(wèn)題。如果你丟掉了第三和第四點(diǎn),我不會(huì)太為難你的。不用說(shuō),如果你能得到后兩點(diǎn),那么你的被雇用前景越來(lái)越光明了。


          代碼例子(Code examples)

          12 . 下面的代碼輸出是什么,為什么?

          void foo(void)
          {
              unsigned int a = 6;
              int b = -20;
              (a+b > 6) ? puts("> 6") : puts("<= 6");
          }
          這個(gè)問(wèn)題測(cè)試你是否懂得C語(yǔ)言中的整數(shù)自動(dòng)轉(zhuǎn)換原則,我發(fā)現(xiàn)有些開(kāi)發(fā)者懂得極少這些東西。不管如何,這無(wú)符號(hào)整型問(wèn)題的答案是輸出是 ">6"。原因是當(dāng)表達(dá)式中存在有符號(hào)類型和無(wú)符號(hào)類型時(shí)所有的操作數(shù)都自動(dòng)轉(zhuǎn)換為無(wú)符號(hào)類型。因此-20變成了一個(gè)非常大的正整數(shù),所以該表達(dá)式計(jì)算出的結(jié)果大于6。這一點(diǎn)對(duì)于應(yīng)當(dāng)頻繁用到無(wú)符號(hào)數(shù)據(jù)類型的嵌入式系統(tǒng)來(lái)說(shuō)是豐常重要的。如果你答錯(cuò)了這個(gè)問(wèn)題,你也就到了得不到這份工作的邊緣。

          13. 評(píng)價(jià)下面的代碼片斷:

          unsigned int zero = 0;
          unsigned int compzero = 0xFFFF;
          /*1's complement of zero */

          對(duì)于一個(gè)int型不是16位的處理器為說(shuō),上面的代碼是不正確的。應(yīng)編寫(xiě)如下:

          unsigned int compzero = ~0;

          這一問(wèn)題真正能揭露出應(yīng)試者是否懂得處理器字長(zhǎng)的重要性。在我的經(jīng)驗(yàn)里,好的嵌入式程序員非常準(zhǔn)確地明白硬件的細(xì)節(jié)和它的局限,然而PC機(jī)程序往往把硬件作為一個(gè)無(wú)法避免的煩惱。
          到了這個(gè)階段,應(yīng)試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應(yīng)試者不是很好,那么這個(gè)測(cè)試就在這里結(jié)束了。但如果顯然應(yīng)試者做得不錯(cuò),那么我就扔出下面的追加問(wèn)題,這些問(wèn)題是比較難的,我想僅僅非常優(yōu)秀的應(yīng)試者能做得不錯(cuò)。提出這些問(wèn)題,我希望更多看到應(yīng)試者應(yīng)付問(wèn)題的方法,而不是答案。不管如何,你就當(dāng)是這個(gè)娛樂(lè)吧...


          動(dòng)態(tài)內(nèi)存分配(Dynamic memory allocation)

          14. 盡管不像非嵌入式計(jì)算機(jī)那么常見(jiàn),嵌入式系統(tǒng)還是有從堆(heap)中動(dòng)態(tài)分配內(nèi)存的過(guò)程的。那么嵌入式系統(tǒng)中,動(dòng)態(tài)分配內(nèi)存可能發(fā)生的問(wèn)題是什么?
          這里,我期望應(yīng)試者能提到內(nèi)存碎片,碎片收集的問(wèn)題,變量的持行時(shí)間等等。這個(gè)主題已經(jīng)在ESP雜志中被廣泛地討論過(guò)了(主要是 P.J. Plauger, 他的解釋遠(yuǎn)遠(yuǎn)超過(guò)我這里能提到的任何解釋),所有回過(guò)頭看一下這些雜志吧!讓?xiě)?yīng)試者進(jìn)入一種虛假的安全感覺(jué)后,我拿出這么一個(gè)小節(jié)目:
          下面的代碼片段的輸出是什么,為什么?

          char *ptr;
          if ((ptr = (char *)malloc(0)) == NULL)
              puts("Got a null pointer");
          else
              puts("Got a valid pointer");

          這是一個(gè)有趣的問(wèn)題。最近在我的一個(gè)同事不經(jīng)意把0值傳給了函數(shù)malloc,得到了一個(gè)合法的指針之后,我才想到這個(gè)問(wèn)題。這就是上面的代碼,該代碼的輸出是"Got a valid pointer"。我用這個(gè)來(lái)開(kāi)始討論這樣的一問(wèn)題,看看被面試者是否想到庫(kù)例程這樣做是正確。得到正確的答案固然重要,但解決問(wèn)題的方法和你做決定的基本原理更重要些。

          Typedef
           
          15 Typedef 在C語(yǔ)言中頻繁用以聲明一個(gè)已經(jīng)存在的數(shù)據(jù)類型的同義字。也可以用預(yù)處理器做類似的事。例如,思考一下下面的例子:

          #define dPS struct s *
          typedef struct s * tPS;

          以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個(gè)指向結(jié)構(gòu)s指針。哪種方法更好呢?(如果有的話)為什么?
          這是一個(gè)非常微妙的問(wèn)題,任何人答對(duì)這個(gè)問(wèn)題(正當(dāng)?shù)脑颍┦菓?yīng)當(dāng)被恭喜的。答案是:typedef更好。思考下面的例子:

          dPS p1,p2;
          tPS p3,p4;

          第一個(gè)擴(kuò)展為

          struct s * p1, p2;
          .
          上面的代碼定義p1為一個(gè)指向結(jié)構(gòu)的指,p2為一個(gè)實(shí)際的結(jié)構(gòu),這也許不是你想要的。第二個(gè)例子正確地定義了p3 和p4 兩個(gè)指針。



          晦澀的語(yǔ)法

          16 . C語(yǔ)言同意一些令人震驚的結(jié)構(gòu),下面的結(jié)構(gòu)是合法的嗎,如果是它做些什么?

          int a = 5, b = 7, c;
          c = a+++b;

          這個(gè)問(wèn)題將做為這個(gè)測(cè)驗(yàn)的一個(gè)愉快的結(jié)尾。不管你相不相信,上面的例子是完全合乎語(yǔ)法的。問(wèn)題是編譯器如何處理它?水平不高的編譯作者實(shí)際上會(huì)爭(zhēng)論這個(gè)問(wèn)題,根據(jù)最處理原則,編譯器應(yīng)當(dāng)能處理盡可能所有合法的用法。因此,上面的代碼被處理成:

          c = a++ + b;

          因此, 這段代碼持行后a = 6, b = 7, c = 12。
          如果你知道答案,或猜出正確答案,做得好。如果你不知道答案,我也不把這個(gè)當(dāng)作問(wèn)題。我發(fā)現(xiàn)這個(gè)問(wèn)題的最大好處是這是一個(gè)關(guān)于代碼編寫(xiě)風(fēng)格,代碼的可讀性,代碼的可修改性的好的話題。


          好了,伙計(jì)們,你現(xiàn)在已經(jīng)做完所有的測(cè)試了。這就是我出的C語(yǔ)言測(cè)試題,我懷著愉快的心情寫(xiě)完它,希望你以同樣的心情讀完它。如果是認(rèn)為這是一個(gè)好的測(cè)試,那么盡量都用到你的找工作的過(guò)程中去吧。天知道也許過(guò)個(gè)一兩年,我就不做現(xiàn)在的工作,也需要找一個(gè)。

          作者介紹:
                  Nigel Jones 是一個(gè)顧問(wèn),現(xiàn)在住在Maryland,當(dāng)他不在水下時(shí),你能在多個(gè)范圍的嵌入項(xiàng)目中找到他。 他很高興能收到讀者的來(lái)信,他的email地址是: NAJones@compuserve.com

          參考文獻(xiàn)
          1) Jones, Nigel, "In Praise of the #error directive," Embedded Systems Programming, September 1999, p. 114.
          2) Jones, Nigel, " Efficient C Code for Eight-bit MCUs ," Embedded Systems Programming, November 1998, p. 66.


          [顯示打印版本]

          相關(guān)文章

          • No Relative Articles.

          相關(guān)評(píng)論   發(fā)表評(píng)論

          • leslie  [2005-04-08]

            挺考驗(yàn)基本知識(shí)的

          posted @ 2008-11-04 21:27 poower 閱讀(188) | 評(píng)論 (0)編輯 收藏
          主站蜘蛛池模板: 高雄市| 丹凤县| 镶黄旗| 布拖县| 廉江市| 三江| 井冈山市| 观塘区| 元氏县| 锡林浩特市| 时尚| 鲁山县| 曲水县| 民乐县| 布尔津县| 珲春市| 长丰县| 抚松县| 松滋市| 泗阳县| 明溪县| 综艺| 云浮市| 天台县| 庄河市| 六盘水市| 开封市| 乐清市| 秦安县| 淮南市| 江川县| 繁峙县| 许昌县| 永仁县| 潜山县| 聊城市| 科尔| 沁水县| 遂昌县| 宁津县| 许昌市|