隨筆-144  評論-80  文章-1  trackbacks-0

          一次偶然的情況下我發(fā)現(xiàn)以下代碼竟然無法被編譯通過(如果你的編譯器,比如VC6或VC2003,允許它編譯通過,我想你首先應(yīng)該換個編譯器,比如GCC或VC2005):
          void foo( const char* [] ) { }
          int main( void )
          {
              char* s[2];
              foo( s );
          }

          簡化成更一般的形式是:
          char** p1 = 0;
          const char** p2 = p1;

          錯誤是:invalid conversion from `char**' to `const char**'.

          lostpencil更加仔細,使用C編譯器給出的是一個警告:
          initialization from incompatible pointer type.

          隨后hpho給出了合理的解釋,同時comp.lang.c++.moderated上的Ulrich Eckhardt也用代碼進行了說明。

          用代碼來說明最直觀了:
          const char* s = "abc";
          int main( void )
          {
              char* p0 = 0;
              char** p1 = &p0;
              const char** p2 = p1;
          // 先假設(shè)這一句是合法的 ( 測試時,可以先強制類型轉(zhuǎn)化一下 )
              *p2 = s;
              *p0 = 'A';
          // 通過p0在修改不應(yīng)該被修改的s,這顯然和const相違背,其運行結(jié)果不可知。
          }




          看了 **的 想到的
          tekyDec 29, 2005 -  Show original item

          看完后.明白**講的為什么char** 不能自動轉(zhuǎn)化為 const char**,(原文)但對我影響最深的是下面的話:

          ==================================================================
          char *p="abc" 能不能編譯通過要看你使用的編譯器。鑒于大量遺留代碼的存在,大部分編譯器允許其通過,或者給個警告。當(dāng)然,程序員自己必須保證絕不去修改其值。

          程序員不應(yīng)該在代碼中出現(xiàn)*p='A'這樣的語句。這是當(dāng)初約定好了的:編譯器允許char *p="abc"通過,而程序員保證不去修改它。
          b. *p='A'編譯時應(yīng)該允許通過,因為單就這條語句而言,它完全合法。
          c. 運行時*p='A'能不能通過要看實際的運行環(huán)境,包括你使用的操作系統(tǒng)、編譯器、編譯器選項 等等,一句話,其運行結(jié)果由不得你,且不應(yīng)該由你去關(guān)心,因為這種行為本身已經(jīng)違反約定了。
          ==================================================================

          工作關(guān)系吧,用CString 和string用的太多了,很少這樣定義字符串 char *p=“abcde“了
          匝一看,還不適應(yīng),:(,漸漸的回想才想起一些來(哎,還是太生疏,趕快寫下來,以后別忘了)

          這樣定義的字符串char *p=“abcde“ ; char *p1=“123445667“;

          正如上面提到的是不能再 *p='A',運行的時候會出錯,同樣,strcpy(p,p1)也會出錯喲,

          "abcde"字符串可以看做是個常量字符串了,是不能被修改的,

          但如果 char p[]=“abcde“ 這樣定義,就沒有問題,你可以修改*p='A',只要不越界就ok.

          并且發(fā)現(xiàn)這樣兩種定義
          char *p=“abcde“

          char p[]=“abcde“

          在運行的時候,p指向的地址也不是一樣的,可見char *p=“abcde“還是有特殊的處理 :),具體怎么處理就不知道了,高手請指教:)


          隨著測試,又發(fā)現(xiàn)個問題,可能是個老問題了吧:


          int main(int argc, char* argv[])
          {
           int t[10];
           char p1[7]="123456";
           const char *p2="1234567890123213123";
           
           int len(0);
           
            //*p1='C';  err

           len=strlen(p1);
           printf("%d\n",len);
           
           strcpy(p1,p2);   ///??????????
           
           printf("%s\n",p1);
           
           len=strlen(p1);
           
           printf("%d\n",len);
           return 0;
          }

          我定義的是7個字符數(shù)組, 但用strcpy把p2拷到p1中,p1是放不下的,但程序卻正常執(zhí)行,warning ,err都沒有,運行也正常?


          輸出

          6
          1234567890123213123
          19

          應(yīng)該是使用內(nèi)存越界了阿??怎么會正常運行呢?

          難道對于內(nèi)存越界的使用,運氣好才崩潰表現(xiàn)出來,運氣不好就正常運行??


           

          posted on 2005-12-29 23:00 小力力力 閱讀(3901) 評論(1)  編輯  收藏 所屬分類: C/C++

          評論:
          # re: 為什么 char** 不能自動轉(zhuǎn)化為 const char** (轉(zhuǎn)) 2006-06-04 15:24 | Damnation
          對于你的最后一個問題,也就是所謂的Buffer Overrun,由于老舊的strcpy的不安全性,使得內(nèi)存(字符串)拷貝越界。

          但是結(jié)果會如何則取決于當(dāng)時棧框架(Stack Frame)的情況,如果越界到儲存返回地址的話,則極有可能會崩潰,運氣好(也可以說是差)的話,則會跳到某未知指令,然后繼續(xù)執(zhí)行……(程序員最大的災(zāi)難)黑客也可以通過這種手段來改變程序的流程。VC2005好像可以開啟對Buffer Overrun的檢測,原理就是在存返回地址的位置前放置一個防護碼,每次執(zhí)行RET指令前先檢查一下防護碼的正確性,如果不正確,則說明IP已經(jīng)被重寫了。

          至于為什么上面的程序可以正常運行,是因為在p1前面的int t[10]起到了緩沖作用,strcpy把部分內(nèi)存越界拷貝到了那數(shù)組里(記住數(shù)值是由高位到地位進棧,所以數(shù)組的地址比字符串高),沒有抹掉返回地址,所以程序可以正常運行。

          不過從VC2005開始,編譯器已經(jīng)禁止使用大部分的strxxx之類的函數(shù)了,而鼓勵程序員使用strxxx_s之類的安全函數(shù)。  回復(fù)  更多評論
            
          主站蜘蛛池模板: 七台河市| 泰和县| 辛集市| 汉寿县| 敖汉旗| 津南区| 达孜县| 福安市| 霸州市| 八宿县| 咸丰县| 肥城市| 临夏县| 图木舒克市| 樟树市| 安徽省| 方山县| 丹棱县| 抚宁县| 如皋市| 南江县| 马山县| 浦县| 凤翔县| 息烽县| 岗巴县| 兴国县| 洛阳市| 揭阳市| 闽清县| 土默特右旗| 三明市| 怀来县| 洛扎县| 镇赉县| 南宁市| 康乐县| 阜新| 新化县| 五峰| 开鲁县|