【问题标题】:C++ pointer value changes with static_castC++ 指针值随 static_cast 变化
【发布时间】:2016-05-31 14:50:48
【问题描述】:

我看到尝试结合 C++ 和 C 代码的奇怪行为。我在 C 代码中使用 C++ 类,在类中使用 static_castvoid*。这是通过以下方式完成的。

//C++ code
void* newCSPI() {
    return static_cast<void*>(new XSpi);
}

这个函数在头文件中声明如下。

//C++ code
extern "C" void* newCSPI(void);

然后我可以在 C 代码中调用 C++ 函数。下面是其他功能的实现示例。

//C++ code
void selectCSlave(void* spi) {
    static_cast<SPI*>(spi)->selectSlave();
}

这个函数也在头文件中声明为extern "C"

这个转换函数实现如下。

//C++ code
void SPI::selectSlave(void) {
    // Select the slave by setting the slave select to low
    XGpio_DiscreteWrite(&slaveSelectDevice, 1, 0x00);
}

我正在尝试执行以下代码块。除了最后一行,一切都成功了。

//C code

void* spi = newCSPI();

/* Select device. */
selectCSlave(spi);

/* Transfer data over SPI*/
transferC(spi, MOSI, MISO, ByteNum);

// It breaks here //

/* Transfer data over SPI*/
transferC(spi, MOSI, MISO, ByteNum);

/* Un-select device. */
deselectCSlave(spi);

在第二次transferC(spi) 调用期间,指针以某种方式改变了值。在强制转换函数内部,指针仍然具有相同的值。在它被转换为的函数内部,值会发生变化。实现与第一个 transferC(spi) 完全相同,它确实有效。这两个调用之间没有代码。

我不明白为什么值会突然改变。我在这里错过了什么?

deselectCSlave()SPI::deselectSlave(void) 的代码:

void deselectCSlave(void* Cspi) {
    static_cast<SPI*>(Cspi)->deselectSlave();
}

void SPI::deselectSlave(void) {
    // Deselects the slave by setting the slave select to high
    XGpio_DiscreteWrite(&slaveSelectDevice, 1, 0xFF);
}

0x000xFF 是正在写入的值。

【问题讨论】:

  • 尚未阅读所有内容,但您可以为 typedef 使用不透明的结构定义,在您的实现中节省大量的转换。
  • 请提供minimal reproducible example。此外,void* 的 typedef 确实令人困惑——尤其是当 CSPIvoid*SPI 实际上是某种类型时。
  • 是什么让您认为价值发生了变化?你从调试器告诉?也许调试器显示了错误的东西。代码还能用吗?
  • @KABoissonneault 调试器确实显示了不同的值。指向的对象的所有属性也已更改,此时代码不再起作用。它在static_cast 调用期间被更改,因此在底层函数中是不同的和错误的。
  • deselectCSlave() 中的代码是什么?当您使用调试器通过监视变量进入该函数时,您是否看到它发生变化的点?

标签: c pointers c++11


【解决方案1】:

如果您将指针转换为void*,则您可以对该值进行的唯一转换是返回到您转换为void*特定类型(嗯,您也可以将其转换为 char*)。

所以当你这样做时:

return static_cast<void*>(new XSpi);

撤消该转换的唯一方法是将其转换为XSpi*。因此,您后来的演员阵容:

static_cast<SPI*>(spi)->selectSlave();

这是违法的。

你可能想做的是:

return static_cast<void*>(static_cast<SPI*>(new XSpi));

那会先把它转换成基类(大概是SPI),然后再转换成void*

【讨论】:

  • 这给出了以下错误:invalid static_cast from type XSpi* to type SPI*
  • @Etruscian:唯一无效的原因是SPIXSpi 是两个完全不相关的 类。也就是说,SPI 不是XSpi 的基础。我用它可能起作用的唯一方法回答了你的问题。您是说您的代码从根本上功能失调。如果您的代码没有损坏,请以minimal reproducible example 的形式实际发布您的代码,以便我们了解发生了什么。
  • 如果一个继承自另一个,则应该是 SPI * 和 XSpi* 之间的 dynamic_cast
  • @sokkyoku:如果 SPI 是基类,则不会。 static_cast 派生类到基类总是合法的。相反,需要dynamic_cast(除非您对该实例的类型有特定的了解)。
  • @NicolBolas 感谢您的评论,我解决了这个问题。 newCSPI(void) 的返回语句应该是:return static_cast&lt;void*&gt;(new SPI); XSpi 是用 C 定义的结构,这使得从它转换类指针是非法的。 SPI 类使用了这个结构,这引起了我的困惑。
猜你喜欢
  • 1970-01-01
  • 2018-12-17
  • 1970-01-01
  • 2014-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 2019-05-26
  • 2017-11-30
相关资源
最近更新 更多