理解神秘的C ++语句

时间:2014-03-28 09:06:21

标签: c++ arduino reinterpret-cast

我来自使用VB.NET的.NET编程,这是我第一个基于Arduino的应用程序的C开发。

阅读Arduino头文件(为.ToString寻找__FlashStringHelper方法之类的内容)我偶然发现了下一个#define

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

首先我理解:

这是一个名为string_literal的参数的宏,此参数以某种方式用于括号内的表达式中。这就是全部!

这些<>符号是什么,*指针突然签名?

2 个答案:

答案 0 :(得分:8)

常规类型转换
在C ++中,有各种类型的强制类型可用于在类型之间进行转换。它们很重要,因为C ++是一种强类型语言,并且编译器不一定知道类型之间的任何给定转换是安全的还是合理的。默认情况下,它会发出错误或警告,除非您明确告诉它该做什么。

所有C ++演员表都具有以下格式:

x_cast <new_type> (expression)

x_cast可以是以下之一:static_castdynamic_castreinterpret_castconst_cast

如果要强制编译器在不相关的指针类型之间进行转换,则使用重新解释转换。结果是指向内存中完全相同的数据的指针。但是,它将被处理(或解释),就好像它是一个不同的类型,这可以允许一些有趣的操作。

例如,假设您有一个指向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。就其本身而言,它不会做任何坏事。结果将完全无用,因为float的基础二进制表示如果您尝试像int那样处理它是没有意义的。

相同的方法可以用于对象,让您解释一个类的实例,就好像它是一个不同的实例。但是,它不进行任何智能转换。它只是强制原始二进制数据以不同的方式处理,这意味着你必须非常确信重新解释是有意义的。

<强> 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 ++的一个有趣的方面 - 你可以实际调用一个不存在的对象的方法,只要该对象不试图访问不存在的成员数据。

答案 1 :(得分:2)

reinterpret_cast运算符用于类型转换。它是将一种指针类型转换为另一种指针类型。

此处PSTR经过类型转换(转换)为__FlashStringHelper*