<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          keil大常量計算問題

          作者: 時間:2016-11-26 來源:網(wǎng)絡(luò) 收藏
          Keil C51是與ANSI C兼容的編譯器,ANSI C規(guī)范規(guī)定十進制整數(shù)常量的默認數(shù)據(jù)類型是int、long int和unsigned long int的其中一種,對給定的常量是其中的哪一種要看這個常量的實際大小,如果常數(shù)在-32768~32767之間則按int類型處理,如果按int類型處理會溢出就考慮long int或更大的數(shù)據(jù)類型unsigned long int??傊?,編譯器總是按盡可能的原則指定常量的類型。

          但這一原則并不總能奏效,當(dāng)兩個常量做運算時就可能導(dǎo)致溢出。如:
          #define SYSCLK22118400// SYSCLK in Hz (22.1184 MHz external crystal oscillator)
          #define SLIDER_REST_TIME100// in ms,slider rest time
          #define REST_DELAYSYSCLK * SLIDER_REST_TIME / (65536 * 1000)
          unsigned char i;
          i = REST_DELAY;
          keil c51中運行i為0xE1,即225,并不是期望的結(jié)果22118400 * 100 / (65536 * 1000) = 33.75,取整為33。原因分析如下:
          宏替換后為:i = 22118400 * 100 / (65536 * 1000);,編譯器首先為22118400定義類型,因為22118400不在int的表示范圍內(nèi),而在long int的范圍-2147483648~2147483647內(nèi),所以22118400按long int類型處理,在做乘積運算時100被自動按long int處理,22118400 * 100將按兩帶符號長整型常量進行運算,運算結(jié)果仍為帶符號長整型,結(jié)果寫成十六進制是0x83D60000,其十進制是-2083127296,顯然出現(xiàn)了溢出錯誤。keil編譯器并沒有給出任何錯誤或警告提示信息(VC++6.0還給出警告warning C4307: * : integral constant overflow),繼續(xù)進行下一個運算65536 * 1000,結(jié)果為帶符號長整型,十六進制為0x3E80000,十進制為65536000,最后按兩長整型除法計算-2083127296 / 65536000,結(jié)果為0xFFFFFFE1,由于i為字符類型,取0xFFFFFFE1的最低有效字節(jié)為0xE1賦值給i,i的最終值為0xE1。
          解決這種溢出錯誤的方法用C語言的一個術(shù)語就是“提升”(promotion),拿上例來說就是將22118400指定為無符號長整型,即:
          #define SYSCLK22118400UL
          注:雖然只要將22118400、100、65536和1000四個常數(shù)中的一個指定為無符號長整型即可得到正確的結(jié)果,但考慮到可讀性及規(guī)范性,應(yīng)選擇大整數(shù)指定其類型。
          小結(jié):按C51編譯器的默認類型整數(shù)常量運算可能出現(xiàn)溢出錯誤,對大整數(shù)應(yīng)指定其數(shù)據(jù)類型以避免出現(xiàn)可能的運算錯誤。

          本文引用地址:http://www.ex-cimer.com/article/201611/321607.htm

          轉(zhuǎn)自:幽幽靈貓

          http://www.cnblogs.com/civet/archive/2011/05/31/2064959.html
          /////////////
          近日做射頻系統(tǒng),一個簡單的MCU系統(tǒng),程序全部用C語言設(shè)計,開發(fā)環(huán)境為盜版的Keil,用到定時器定義一個60秒的時間時,如此定義:
          uint16time;//16位變量

          time=60*1000/TMRCYC//TMRCYC=5,定時器中斷間隔為5ms
          //time總時間60s
          實際運行時,60s定時總是感覺不到,也就是說60s根本就沒定義成功。
          理論上講,time=12000,比16位最大值65535小,應(yīng)該沒問題,但實際就是不行,以前沒怎么用過Keil,所以也沒注意這個問題,是否其他編譯器也有這個問題不得而知,最后,定義改為:
          time=60*1000L/TMRCYC//常量1000后加L
          問題解決。
          但仍未完全明白其中道理,難道是編譯器的問題,在此拋磚引玉,鄙人雖說也有幾年程序經(jīng)驗,但哎,偏偏這么一個看似基礎(chǔ)性的東西卻不懂,希望有大蝦們解釋下,可能對你們來說問題很簡單,但不懂或沒有遇見的小菜們卻是有千千萬萬,你們就權(quán)當(dāng)做好事了。
          ///http://bbs.21ic.com/icview-43268-1-1.html
          ///
          上一篇下一篇共25篇

          編程中無窮大常量的設(shè)定技巧2012年11月22日 13:08:05

          轉(zhuǎn)自http://aikilis.tk/

          如果問題中各數(shù)據(jù)的范圍明確,那么無窮大的設(shè)定不是問題,在不明確的情況下,很多程序員都取0x7fffffff作為無窮大,因為這是32-bit int的最大值。如果這個無窮大只用于一般的比較(比如求最小值時min變量的初值),那么0x7fffffff確實是一個完美的選擇,但是在更多的情況下,0x7fffffff并不是一個好的選擇。

          1. 很多時候我們并不只是單純拿無窮大來作比較,而是會運算后再做比較,例如在大部分最短路徑算法中都會使用的松弛操作:
            if (d[u]+w[u][v]我們知道如果u,v之間沒有邊,那么w[u][v]=INF,如果我們的INF取0x7fffffff,那么d[u]+w[u][v]會溢出而變成負數(shù),我們的松弛操作便出錯了,更一般的說,0x7fffffff不能滿足“無窮大加一個有窮的數(shù)依然是無窮大”,它變成了一個很小的負數(shù)。
          2. 除了要滿足加上一個常數(shù)依然是無窮大之外,我們的常量還應(yīng)該滿足“無窮大加無窮大依然是無窮大”,至少兩個無窮大相加不應(yīng)該出現(xiàn)災(zāi)難性的錯誤,這一點上0x7fffffff依然不能滿足我們。

          所以我們需要一個更好的家伙來頂替0x7fffffff,最嚴謹?shù)霓k法當(dāng)然是對無窮大進行特別處理而不是找一個很大很大的常量來代替它(或者說模擬它),但是這樣會讓我們的編程過程變得很麻煩。在我讀過的代碼中,最精巧的無窮大常量取值是0x3f3f3f3f,我不知道是誰最先開始使用這個精妙的常量來做無窮大,不過我的確是從一位不認識的ACMer(ID:Staginner)的博客上學(xué)到的,他/她的很多代碼中都使用了這個常量,于是我自己也嘗試了一下,發(fā)現(xiàn)非常好用,而當(dāng)我對這個常量做更深入的分析時,就發(fā)現(xiàn)它真的是非常精巧了。

          1. 0x3f3f3f3f的十進制是1061109567,也就是10^9級別的(和0x7fffffff一個數(shù)量級),而一般場合下的數(shù)據(jù)都是小于10^9的,所以它可以作為無窮大使用而不致出現(xiàn)數(shù)據(jù)大于無窮大的情形。
          2. 另一方面,由于一般的數(shù)據(jù)都不會大于10^9,所以當(dāng)我們把無窮大加上一個數(shù)據(jù)時,它并不會溢出(這就滿足了“無窮大加一個有窮的數(shù)依然是無窮大”),事實上0x3f3f3f3f+0x3f3f3f3f=2122219134,這非常大但卻沒有超過32-bit int的表示范圍,所以0x3f3f3f3f還滿足了我們“無窮大加無窮大還是無窮大”的需求。
          3. 最后,0x3f3f3f3f還能給我們帶來一個意想不到的額外好處:如果我們想要將某個數(shù)組清零,我們通常會使用memset(a,0,sizeof(a))這樣的代碼來實現(xiàn)(方便而高效),但是當(dāng)我們想將某個數(shù)組全部賦值為無窮大時(例如解決圖論問題時鄰接矩陣的初始化),就不能使用memset函數(shù)而得自己寫循環(huán)了(寫這些不重要的代碼真的很痛苦),我們知道這是因為memset是按字節(jié)操作的,它能夠?qū)?shù)組清零是因為0的每個字節(jié)都是0,現(xiàn)在好了,如果我們將無窮大設(shè)為0x3f3f3f3f,那么奇跡就發(fā)生了,0x3f3f3f3f的每個字節(jié)都是0x3f!所以要把一段內(nèi)存全部置為無窮大,我們只需要memset(a,0x3f,sizeof(a))。

          所以在通常的場合下,0x3f3f3f3f真的是一個非常棒的選擇。




          關(guān)鍵詞: keil大常量計

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();