2014-03-28 46 views
2

我來自.NET編程使用VB.NET,這是我的第一個基於Arduino的應用程序的C開發。瞭解神祕的C++語句

通過Arduino的頭文件(尋找類似的__FlashStringHelper一個.ToString方法),我偶然發現了下一個#define

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal))) 

首先我是這麼理解閱讀:

這是一個宏用參數名稱爲string_literal,並且此參數在括號內的表達式中以某種方式使用。就這樣!

這些是什麼<,>標誌和*指針突然出現?

+0

錯誤的語言。這是C++,而不是C,我編輯了標題和標籤。 – Jens

+0

你可以閱讀'reinterpret_cast' [例如這裏](http://en.cppreference.com/w/cpp/language/reinterpret_cast)。總之,它是C風格演員的C++變體。 –

+0

術語提示:'#define'被稱爲*預處理指令*,整行a *宏定義*(用於函數式宏'F')。 – Jens

回答

8

普通型鑄造
在C++中,存在多種類型的可用於類型之間轉換鑄件。它們很重要,因爲C++是一種強類型語言,編譯器不一定知道類型之間的任何轉換是安全的還是合理的。默認情況下,它會發出錯誤或警告,除非您明確告訴它該做什麼。

所有C++鑄件具有以下格式:

x_cast <new_type> (expression) 

x_cast可以是下列之一:static_castdynamic_castreinterpret_cast,或者const_cast

當您要強制編譯器在不相關的指針類型之間進行轉換時,使用reinterpret強制轉換。結果是一個指向內存中完全相同的數據的指針。然而,它將被處理(或解釋),就好像它是一種不同的類型,它可以允許一些有趣的操作。

例如,假設您有一個指向4字節無符號整數的指針,並且要單獨訪問每個字節。你可以做,通過重新解釋指針1個字節的類型,就像這樣:

uint32_t num = 12345; 
uint32_t *p1 = &num; 

uint8_t *p2 = reinterpret_cast<uint8_t*>(p1); 

// Access the individual bytes: 
uint8_t byte0 = p2[0]; 
uint8_t byte1 = p2[1]; 
uint8_t byte2 = p2[2]; 
uint8_t byte3 = p2[3]; 

指針p1p2都指向存儲在num變量中的數據。不同之處在於,通過p2訪問它將導致編譯器將其視爲1字節無符號整數(而不是原始4字節類型)。這使您可以提取/操作原始變量中不同位置的單個字節。

對於這樣一個簡單的例子,reinterpret_cast是相當安全的。然而,在許多情況下,它可能會發生非常嚴重的錯誤,或者如果沒有謹慎使用,根本就沒有用處。一個例子是試圖重新解釋一個float指針作爲int。就其本身而言,它不會做任何壞事。但結果將是完全無用的,因爲如果您嘗試像int那樣處理它,則float的基礎二進制表示形式沒有任何意義。

相同的方法可以用於對象,讓您可以將一個類的實例解釋爲不同的實例。但是,它不做任何智能轉換。它只是迫使原始二進制數據以不同的方式處理,這意味着您必須非常有信心重新解釋纔有意義。

的Arduino
您在Arduino的文件中標識的線是相當複雜的,當它完全展開,所以我們將它分解一下。正如我認爲你已經確定的那樣,它定義了一個名爲F()的宏,該宏使用了一個名爲string_literal的參數。

顧名思義,它旨在與字符​​串文字F("like this")一起使用。在表面下,編譯器將字符串文字視爲指向字符數組的指針;或換句話說,char *

F()宏的內部,字符串文字被放入另一個宏,名爲PSTR()。這基本上增加了一大堆其他東西,它告訴編譯器將字符串數據存儲在程序空間(草圖位於Arduino中),而不是SRAM(變量存在的地方)。

在這一點上,reinterpret_cast發揮作用。 PSTR()中的所有內容都很重要,但它並不會真正影響演員看到的數據類型。基本上你可以把它想象作用是這樣的:

char *ptr = "my string data"; 
reinterpret_cast<const __FlashStringHelper *>(ptr); 

__FlashStringHelper是一類,這意味着它的類型無關char *。這就是爲什麼我們需要重新解釋它,所以編譯器知道我們正在爲操作的安全負責。當使用轉換的結果時,它將像指向__FlashStringHelper對象的指針一樣工作,這意味着它的方法可用於訪問/處理字符串數據。

實際上,實際上並沒有創建__FlashStringHelper的實例。底層數據仍然只是我們的字符串文字。這是C++的一個有趣方面 - 只要對象不嘗試訪問不存在的成員數據,實際上可以調用不存在的對象的方法。

+0

非常感謝你布盧姆菲爾德先生:非常明確的解釋,現在我更進一步! – user1737538

2

reinterpret_cast運算符用於類型轉換。它是將一個指針類型轉換爲另一個。

這裏PSTR是類型強制轉換(轉換)到__FlashStringHelper*