C++ 易混淆點(一)

  • 2.1.1 :

    • C++標準規定的各種算術類型的尺寸的最小值, 同時允許編譯器賦予這些類型更大的尺寸.
      比如char的最小尺寸爲8位

    • 執行浮點數運算選用double ,這是因爲float 通常精度不夠而且雙精度浮點
      數和單精度浮點數的計算代價相差無兒。事實上, 對於某些機器來說,雙精度運
      算甚至比單精度還快

  • 2.1.2 :

    • 當我們賦給無符號類型一個超出它表示範圍的值時,結果是初始值對無符號類型表
      示數值總數取棋後的餘數。例如, 8 比特大小的un signe d char 可以表示0 至
      255 區間內的值,如果我們賦了一個區間以外的值,則實際的結果是該值對256
      取模後所得的餘數。因此,把 -1 賦給8 比特大小的uns 工gned char 所得的結果
      是255

    • 當我們賦給帶符號類型一個超出它表示範圍的值時,結果是未定義的( undefined )。
      此時, 程序,可能繼續工作、可能崩潰,也可能生成垃圾數據。

    • 如果表達式裏既有帶符號類型又有無符號類型, 當帶符號類型取值爲負時會出現異
      常結果, 這是因爲帶符號數會自動地轉換成無符號數。例如,在一個形如a*b 的式子
      中,如果a = -1 , b = 1 ,而且a 和b 都是int ,則表達式的值顯然爲- 1 0 然而,如
      果a 是int , 而b 是unsigned , 則結果須視在當前機器上int 所佔位數而定。在我
      們的環境裏,結果是4294967295

  • 2.2.1 :

    • 如果是內置類型的變量未被顯式初始化,它的值由定義的位置決定。定義於任何函數
      體之外的變量被初始化爲0 。然而如6. 1. 1 節(第1 85 頁〉所示, 一種例外情況是,定義
      在函數體內部的內置類型變量將不被初始化( tminitialized ) 。一個未被初始化的內置類型
      變量的值是未定義的(參見2. 1. 2 節, 第33 頁) ,如果試圖拷貝或以其他形式諦問此類值
      將引發錯誤

    • 定義於函數體內的內置類型的對象如果沒有初始化,時值未定義。類的對象
      如果沒有顯式地初始化,則其位由類確定。

  • 2.2.2 :

    • 爲了支持分離式編譯, C←←語言將聲明和定義區分開來。聲明( declaration ) 使得名字
      爲程序所知, 一個文件如果想使用別處定義的名字則必須包含對那個名字的聲明。而定義
      ( defi nition ) 負責創建與名字關聯的實體。
      變量聲明規定了變量的類型和名字, 在這一點上定義與之相同。但是除此之外,定義
      還申請存儲空間,也可能會爲變量賦一個初始值。
      如果想聲明一個變量;而非定義它,就在變量名前添加關鍵字extern ,而且不要顯式
      地初始化變量:

        extern int i ; // 聲明i 而非定義i
          int j ; / / 聲明並定義j
      

      任何包含了顯式初始化的聲明即成爲定義。我們能給由extern 關鍵字標記的變量賦
      一個初始值,但是這麼做也就抵消了extern 的作用。extern 語句如果包含初始值就不
      再是聲明,而變成定義了:
      extern doub1e pi = 3 . 1416 ; // 定義
      在函數體內部,如果試圖初始化一個由extern 關鍵字標記的變革, 將引發錯誤

  • 2.2.3 :

    • C++也爲標準庫保留了一些名字。用戶在自定義的標識符中不能連續出現兩個下
      畫錢,也不能以下畫線緊連大寫字句開頭。此外,定義在函數體外的標識稍不能以下畫線
      開頭。 比如: int _ = 3; 是合法的
  • 2.3.1 :

    • 其他所
      有引用的類型都要和l 與之綁定的對象嚴格匹配。而且,引用只能綁定在對象上,而不能與
      字面值或某個表達式的計算結果綁定在一起, 相關原因將在2 .4 . 1 節詳述:

        int &refVa14 = 10 ; //錯誤· 引用類型的初始值必須是一個對象
          double dval = 3.14 ;
          int &refVa15 = dva1 ; // 錯誤: 此處引用類型的初始位必須是int 型對象
      
  • 2.3.2 :

    • 因爲引用不是對象, 沒有實際地址,所以不能定義指向引用的指針。
  • 2.4 :

    • 默認狀態下, const 對象僅在文件內有效

      當以編譯時初始化的方式定義一個const 對象時,就如對bufSize 的定義一樣:

        const int bufS 工ze = 512; 11 輸入緩衝區大小
      

      編譯器將在編譯過程中把用到該變量的地方都替換成對應的值。也就是說,編譯器會找到
      代碼中所有用到bufSize 的地方,然後用512 替換。
      爲了執行上述替換, 編譯器必須知道變量的初始值。如果程序包含多個文件,則每個
      用了co nst 對象的文件都必須得能訪問到它的初始值纔行。要做到這一點,就必須在每
      一個用到變量的文件中都有對它的定義(參見2.2.2 節, 第4 1 頁)。爲了支持這一用法,
      同時避免對同一變量的重複定義,默認情況下, const 對象被設定爲僅在文件內有效。、
      多個文件中出現了同名的const 變量時,其實等同於在不同文件中分別定義了獨立的變量。
      某些時候有這樣一種const 變量,它的初始值不是一個常量表達式,但又確實有必
      要在文件間共享。這種情況f , 我們不希望編譯器爲每個文件分別生成獨立的變量。相反,
      我們想讓這類const 對象像其他(非常量)對象一樣工作,也就是說,只在一個文件中
      定義const ,而在其他多個文件中聲明並使用它。
      解決的辦法是,對於c o nst 變量不管是聲明還是定義都添加extern 關鍵字, 這樣
      只需定義一次就可以了:

        // file 1 . cc 定義並初始化了一個常壺,該常量能被其他文件訪問
          extern const int bufS 工ze = fcn();
          // file 1 . h 頭文件
          extern const int bufSize ; /1 與f ile 1. cc 中定義的bufS 工ze 是同一個
      

      如上述程序所示, fi1e 1. cc 定義並初始化了bufSize 。因爲這條語句包含了初始值,
      所以它(顯然〉是一次定義。然而,因爲b ufSize 是←個常量,必須用extern 加以限
      定使其被其他文件使用。
      file 1. h 頭文件中的聲明也由extern 做了限定,其作用是指明bufS 工ze 並非本
      文件FiIi 獨有,它的定義將在別處出現。

  • 2.4.1

    • 初始化和對const 的引用

      2 . 3 . 1 節(第46 頁〉提到, 號| 用的類型必須與其所引用對象的類型→致,但是有兩個
      例外。第一種例外情況就是在初始化常量引用時允許用任意表達式作爲初始值,只要該表
      達式的結果能轉換成(參見2.1 .2 節,第3 2 頁)引用的類型叩可。尤其,允許爲一個常量
      引用綁定非常量的對象、字面值, 甚至是個-般表達式:

        int i= 42 ; .
          const int &r1 = i ; // ft許將c ons t in t&#~ 定到一個普通int 對象上
          const int &r2 = 42; // 正確r1 是一個常量引用
          const int &r3 = r1 * 2 ; // 正確r3 是一個常受引用
          int &r4 = r1 * 2 ; // 錯誤r4 是一個普通的非常受引用
      

      要想、理解這種例外情況的原因,陸簡單的辦法是弄清楚當一個常量引用被綁定到另外一種
      類型上時到底發生了什麼:

        doub1e dval = 3 . 14 ;
          const int &ri = dva1 ;
      

      此處ri 引用了一個int 型的數。對口的操作應該是整數運算,但dval 卻是一個雙精
      度浮點數而非整數。因此爲了確保讓rl 綁定一個整數,編譯器把上述代碼變成了如下
      形式:

        const int temp = dval; 1/ 由雙精度浮點數生成一個臨時的整型常量
          const int &ri = temp ; 11 讓rl 綁定這個臨時受
      

      在這種情況下, ri 綁定了一個臨時量( tempo ra ry )對象。所謂臨時量對象就是當編譯器
      而要一個空間來暫存表達式的求值結果時臨時創建的一個未命名的對象。c++程序員們常
      常把臨時量對象簡稱爲臨時量。
      接下來探討當ri 不是常量時,如果執行了類似於上面的初始化過程將帶來什麼樣的
      後果。如果且不是常量,就允許對ri 賦值,這樣就會改變ri 所引用對象的值。注意,
      此時綁定的對象是一個臨時量;而三11:: dvalo 程序員既然讓rl 引用dval , 就肯定想通過
      ri 改變dval 的值,否則幹什麼要給ri 賦值l呢?如此看來, 既然大家基本上不會想着把
      引用綁定到臨時量上, c++語言也就把這種行爲歸爲非法。

  • 2.5.2

    • 和原來另I~些只對應一種特定類型的說明符(比如double) 不|司. auto 讓編譯器通QÐ
      過初始值來推算變量的類型。顯然. auto 定義的變量必須有初始值:

    • 使用auto 也能在一條語句中聲明多個變量。因爲一條聲明語句只能有一個基本數據
      類型,所以該語句中所有變量的初始基本數據類型都必須一樣:

        int i = 0; 
          const int ci = i;
          auto &n = i, *p = &ci   // 錯誤i 的類型是int 而& ci 的類型是const int
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章