c++ - 了解神秘的C++语句

标签 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的参数的宏,该参数在括号内的表达式中以某种方式使用。就这样!

这些<>标志和*指针突然之间是什么?

最佳答案

常规类型转换
在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()中的所有内容都很重要,但是它并不会真正影响 Actor 表看到的数据类型。您基本上可以想象它的行为如下:
char *ptr = "my string data";
reinterpret_cast<const __FlashStringHelper *>(ptr);
__FlashStringHelper是一个类,这意味着它的类型与char *无关。这就是为什么我们需要重新解释它的原因,因此编译器知道我们对操作的安全性负责。使用强制转换的结果时,它将像指向__FlashStringHelper对象的指针一样工作,这意味着可以使用其方法访问/处理字符串数据。

实际上,实际上没有创建__FlashStringHelper的实例。基础数据仍然只是我们的字符串文字。这是C++有趣的方面之一-您可以实际上调用不存在的对象的方法,只要该对象不尝试访问不存在的成员数据即可。

关于c++ - 了解神秘的C++语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22708300/

相关文章:

c++ - reinterpret_cast 从原始内存中获取的指针重新分配是否会导致 UB?

c++ - 使用 C++ 模板更改操作

c++ - 特定共享内存写入操作 (MPI) 的同步

c++ - "Insert before"用于 std::list

javascript - 显示来自数据库 AngularJS 的值

java - 如何在 Java 和 Arduino IDE 中将/* 保存在字符串中?

c++ - 在 Unix/Linux (Ubuntu) 中编译头文件和两个 .cpp 文件

mysql - 从arduino获取数据并通过ethienet存储到数据库中

c++ - 将任意整数转换为 void*

c++ - g++-7.0/访问硬件中 constexpr 函数的不同行为