所以我偶然发现了这段关于arduino内存的代码
void EEPROM_writeDouble(int address, double value)
{
byte* p = (byte*)(void*)&value;
for (int i = 0; i < sizeof(value); i++)
{
EEPROM.write(address++, *p++);
}
}
令我感兴趣的是这行代码byte* p = (byte*)(void*)&value;
做得很完整,但没有弄清楚或者可能。所以我们有一个byte(char)
类型的指针,它接受类型void*
的值的引用并将其转换为字节指针?
答案 0 :(得分:3)
此演员表没有实际原因。代码正在进行类型惩罚,编写代码的程序员可能会感到困惑。尝试从变量中获取单个字节时,可以使用unsigned char*
指针。我假设的是这个例子中的byte
。您无需为此指定void*
指针。
答案 1 :(得分:3)
由于从double*
到byte*
的转换不是有效static_cast
或const_cast
,因此C ++会将请求转换的C样式转换解释为等同于{ {1}}。 (我假设reinterpret_cast
是byte
或unsigned char
的typedef。)
在最初的C ++ 98标准和C ++ 03标准中,基本上没有保证char
会做什么,只是说结果是&#34;实现定义&# 34 ;.因此,单个演员可能会获得指向reinterpret_cast
变量存储开头的指针,但从技术上讲,你不能指望它。
另一方面,示例中的两次转化,从double
到double*
,然后从void*
到void*
,都是有效的byte*
次转化,所以C风格的演员都会有static_cast
的行为。来自(非空)[cv] static_cast
的{{1}}始终保证对象存储开头的static_cast
点,从而产生指针假想void*
重叠void*
对象的存储空间。 (并且从byte
或double
中读取属于不同类型对象的存储,这是严格别名规则的特定例外,所以没关系。)
请注意,从C ++ 11标准开始,unsigned char
的行为以及C风格的强制转换更为某些类型的指针转换指定:([expr.reinterpret.cast] / 7 )
可以将对象指针显式转换为不同类型的对象指针。当{&#34}类型的
char
指向reinterpret_cast
&#34;转换为&#34;指向 cvv
&#34;的结果,结果为T1
cvT2
cvstatic_cast<
如果T2*>(static_cast<
和void*>(v))
都是标准布局类型,T1
的对齐要求不比{{1}更严格或者,如果任一类型为void。将&#34;指针的prvalue转换为T2
&#34;指向T2
&#34;的类型&#34;指针(其中T1
和T1
是对象类型,并且T2
的对齐要求不比T1
更严格,并且返回其原始类型会产生原始指针值。任何其他此类指针转换的结果都未指定。
因此,使用最近的标准模式,不再需要两个演员表。 (代码可能是先前编写的,或者可能仍然需要在多个C ++版本下工作,或者可能只是使用旧习惯编写。虽然使用C ++风格的转换来说明你真正意味着什么样的转换逻辑几乎总是比使用C风格的演员更好的主意。)
答案 2 :(得分:2)
如果(byte *)p
是指针,则标准定义(byte *)(void *)p
与p
相同。
更详细地说,N4659 [expr.reinterpret.cast] / 7将reinterpret_cast<T1 *>(p)
定义为static_cast<T1 *>(static_cast<void *>(p))
,[expr.cast]涵盖两个C风格的强制转换解析为static_cast
在这种情况下。
所以这个演员是多余的,我们可以推测作者并不是很了解这门语言。