C++ 容易忘的基本文法和特性

來源:互聯網
上載者:User

原文連結http://blog.csdn.net/breakerzy/article/details/7271050

標準 C++ 中容易忘記但比較重要和常用的基本文法和特性

這是 C++ 或 C in C++,而不一定是傳統 C 語言的文法和特性

零 0

字面量 0 是基本類型自動適應的,指標請直接使用 0 而不是 NULL 宏,如:

  1. double dval = 0;    // 0 是 double 類型,寫 0.0 多餘  
  2. double dval1 = 1;   // 1 是整數類型,型別提升  
  3. double dval2 = 1.0; // 1.0 是浮點類型  
  4.   
  5. class Widget {  
  6.     virtual void paint(Graphics* g) = 0;  
  7. };  

stddef.h 中支援老代碼的 NULL 定義:

  1. #ifdef __cplusplus  
  2. #define NULL    0               // 0 是各種指標類型  
  3. #else  
  4. #define NULL    ((void *) 0)    // C 中 0 是整數類型  
  5. #endif  
數組由初始化自動確定大小
  1. int a1[] = {1, 2, 4, 8};  
  2. int a2[8] = {1, 2, 4, 8};   // 剩餘元素初始化為 0,相當於 {1, 2, 4, 8, 0, 0, 0, 0};  
  3. int a1[8] = {};             // 或 {0},全 0 的數組  

字串字面量等價於數組 {}:

  1. char s1[] = "abc";  // 相當於 {'a', 'b', 'c', 0}  
  2. char s2[8] = "abc"; // 相當於 {'a', 'b', 'c', 0, 0, 0, 0, 0}  
  3. char s3[8] = "";    // 或 {}, {0},全 0 的數組  

{} 和 "" 僅用於數組初始化,不能賦值,如:s3[8] = "123",請用 strcpy(), memcpy()

數組大小

sizeof: 操作符取得對象和數組的位元組大小(變數或類型)

_countof: 取得數組的元素個數,只應用於數組而非指向數組的指標,在 VC 的 stdlib.h 中定義(C++ 用模板,C 用宏定義),等價於 sizeof(a)/sizeof(a[0])

數組尾哨兵元素位置

C++ 編譯和運行環境保證,數組最後一個元素之後的一個元素的位置(地址)總是可以訪問的,但不保證此地址單元內容可讀寫

與此相對,不保證數組第一個元素之前的一個元素的位置(地址)可以訪問,這鑒於對象、數組的記憶體邊界對齊放置

數組 a[N] 的尾哨兵地址:&a[N], a + N, a + _countof(a)

STL 演算法因此可以操作內部數組:

  1. char a1[]  = "abc123bca";  
  2. size_t c = _s::count(a1, a1 + _countof(a1), 'b');   // a1[] 中 b 的個數  
數組和指標

數組名/指標 + 整數 offset,是以數組 元素單元 為單位

指標和大小類型

請使用以下而不是其它 int 類型,保證 32/64 bit 移植性

這些類型在 stddef.h, cstddef (namespace std), crtdefs.h 中定義

  • size_t: unsigned, sizeof 的結果 位元組大小類型, 指標/地址值, 數組下標或元素個數
  • ptrdiff_t: signed, 指標/地址的差值
  • uintptr_t: unsigned, 指標/地址值, 同 size_t
  • intptr_t: signed, 指標/地址的差值, 同 ptrdiff_t

STL 標準庫中的很多大小和指標差實值型別都是 size_t 和 ptrdiff_t 的別名,如分配器 std::allocator 中:

  1. typedef size_t      size_type;  
  2. typedef ptrdiff_t   difference_type;  
printf 列印指標地址

用 32/64bit 整數自定適應首碼 I,對應 ptrdiff_t (signed) 或 size_t (unsigned)

用 printf 的變長寬度格式化 *

  1. _stprintf_s(buf, _countof(buf), _T("0x%0*IX\n"), sizeof(size_t) * 2, ptr);  

32bit 輸出:0x00000001
64bit 輸出:0x0000000000000001

字串字面量

其類型是 const char_type[N] 數組,N 算上最後結尾 0 字元

大小

"hello": 類型是 const char[6], sizeof() = 6

L"abc中文123": 類型是 const wchar_t[9], sizeof() = 18

"": 類型是 const char[1], sizeof() = 1

常量性

請以 const char_type* 或數組作為字串字面量的初始化、賦值左值

有些編譯器警告報錯非 const 的 char_type* 初始化、賦值 (GCC),但有些編譯時間不報錯 (VC)

  1. char* str = "abc123";  
  2. str[1] = 'B';       // 運行時 access violation  
  3.   
  4. void str_func(char* str);  
  5. str_func("abc123"); // 危險,是否修改 str 的值?  

正確的習慣:

  1. const char* str = "abc123"; // 指標指向字面量的儲存,如 .rdata 唯讀區段  
  2. char str2[] = "abc123";     // 用字母量初始化另一個 char[] 對象的儲存  
  3.   
  4. void str_func(const char* str);  
  5. void str_func2(__out char* str);    // 告訴使用者參數 str 將會修改值,約束性編程  
逸出字元
  1. wchar_t s1[] = L"abc\u4e2d\u6587";          // Unicode/UCS-2: 中 4e2d, 文 6587, Unicode 16 進位轉義 \uhhhh  
  2. char s2[] = "\x61\x62\x63\xd6\xd0\xce\xc4"; // GBK: 中 d0d6, 文 c4ce, 16 進位轉義 \xhh  
  3. char s3[] = "\141\142\143\326\320\316\304"; // 同上, GBK, 8 進位轉義 \ooo  
拼接

編譯階段拼接,空白字元: 空格, TAB, 分行符號

  1. char s[] = "hello"  
  2.            ", world";  
連結方式

字串字面量的連結方式 (internal linkage) 預設使用內部連結方式,相當於使用 static 修飾

以指標類型的模板參數只能使用指向外部連結化物件的指標為例:

  1. template<const char* Name>  
  2. void str_func();  

哪些可以作為 str_func 的模板參數 str_func<Hello>

  1. str_func<"hello">        // 錯誤, 直接寫字面量, 內部連結  
  2. char Hello1[] = "hello"; // 正確, 非 const 的字元數組, 外部連結  
  3. const char Hello2[] = "hello";        // 錯誤, const 全域字元數組, 內部連結, 相當於字面量  
  4. extern const char Hello3[] = "hello"; // 正確, extern 顯式修飾 const 全域字元數組, 外部連結  
結構體初始化

{} 用於初始化 POD 結構和數組,可以嵌套,常用這種方法初始化程式啟動時的配置資料

一旦 struct/class 中有自訂的建構函式,則不能再用 {} 初始化

  1. enum SEX {  
  2.     MALE,  
  3.     FEMALE  
  4. };  
  5.   
  6. // Person 中必須沒有自訂建構函式  
  7. struct Person {  
  8.     int     no;  
  9.     char    nickname[16];  
  10.     char*   name;  
  11.     SEX     sex;  
  12. };  
  13.   
  14. // ss[] 可以是全域或局部變數  
  15. Person ss[] = {{42, "Mark", strdup("Mark Zuckerberg"), MALE},  
  16.                {43, "Page", strdup("Larry Page"), MALE},  
  17.                {44, "Jobs", strdup("Steve Jobs"), MALE}};  
名字空間別名

名字空間可以嵌套,如果名字空間很長可以用別名代替,我習慣用 _n1_n2_n3 的短別名:

  1. namespace _b_al = boost::algorithm;  

請在較小範圍內進行名字空間匯入、短別名代替,切忌放到 .h 中,防止影響範圍擴散

for 迴圈中的 continue 會執行步進語句

以刪除 vector 中特定元素為例,i++ 不能放到 for 的步進語句中:

  1. for (i = vec.begin(); i != vec.end();) {  
  2.     if (if_remove(i)) {  
  3.         i = vec.erase(i);  
  4.         continue;  
  5.     }  
  6.     i++;  
  7. }  
bool 運算式短路求值

expr1 && expr2: 只在 expr1 = true 時,才會對 expr2 求值

expr1 || expr2: 只在 expr1 = false 時,才會對 expr2 求值

這種技巧慣用在後邊的語句依賴前面語句的時候,如:

  1. // 僅當 p != 0 時,才會訪問 p->count  
  2. if (p && p->count > 42)  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.