普通型鑄造
在C++中,存在多種類型的可用於類型之間轉換鑄件。它們很重要,因爲C++是一種強類型語言,編譯器不一定知道類型之間的任何轉換是安全的還是合理的。默認情況下,它會發出錯誤或警告,除非您明確告訴它該做什麼。
所有C++鑄件具有以下格式:
x_cast <new_type> (expression)
x_cast
可以是下列之一:static_cast
,dynamic_cast
,reinterpret_cast
,或者const_cast
。
當您要強制編譯器在不相關的指針類型之間進行轉換時,使用reinterpret強制轉換。結果是一個指向內存中完全相同的數據的指針。然而,它將被處理(或解釋),就好像它是一種不同的類型,它可以允許一些有趣的操作。
例如,假設您有一個指向4字節無符號整數的指針,並且要單獨訪問每個字節。你可以做,通過重新解釋指針1個字節的類型,就像這樣:
uint32_t num = 12345;
uint32_t *p1 = #
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];
指針p1
和p2
都指向存儲在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++的一個有趣方面 - 只要對象不嘗試訪問不存在的成員數據,實際上可以調用不存在的對象的方法。
錯誤的語言。這是C++,而不是C,我編輯了標題和標籤。 – Jens
你可以閱讀'reinterpret_cast' [例如這裏](http://en.cppreference.com/w/cpp/language/reinterpret_cast)。總之,它是C風格演員的C++變體。 –
術語提示:'#define'被稱爲*預處理指令*,整行a *宏定義*(用於函數式宏'F')。 – Jens