如何从C传递char*到CPP?

3
一些背景信息: 我有一份C代码库,它是一个更大系统(全部都是C)的一部分。对于这个特定的C库的部分,必须创建一个GUI,允许用户使用选项。为了支持跨平台,我选择了QT作为GUI工具。 我使用Eclipse和MinGW作为IDE和编译器(但我认为问题更多地与语言相关而不是编译器?)。
在QT中,我创建了一个小部件,它持有指向C中实现的结构体的指针,该结构体包含指向执行C库逻辑的几个函数的指针。
//QTWidget.cpp
extern "C" {
#include "c-src/CLogic.h"
//extern char* textHelper;
}

QTWidget::QTWidget(QWidget *parent)
{
    //rtw is a struct that contains a function pointer to a member of QTWidget
    this->rtw.displayText = &QTWidget::displayText;
    this->clogic = CLogic_getInstance(&rtw);
}

//Public SLOT, connected to a button's clicked SIGNAL
void QTWidget::buttonClicked()
{
    this->clogic->buttonClicked();
}

void QTWidget::displayText(char *text, int position)
{
    //I've tried creating a QString from the char*, but this does not work at all.
    //ui.textItem->setText(textHelper);
    ui.textItem->setText(text);
}

当用户在GUI中按下按钮时,方法QTWidget::buttonClicked()被调用,它告诉C库去执行某些操作。请注意,CLogic结构体有一个对QTWidget的引用,以struct RefToWidget的形式持有一个函数指针。
//CLogic.c
static CLogic instance;

void CLogic_buttonClicked()
{
    //I've tried several variants here, such as making a global 
    //char* textHelper = "Hello World"; 
    //that is referenced by using the "extern" keyword in the CPP file above.
    instance.rtw->displayText("Hello World", 1);
}
CLogic* CLogic_getInstance(RefToWidget *rtw)
{
    instance.rtw = rtw;
    instance.buttonClicked = &CLogic_buttonClicked();
}

在调试此程序时,我发现所有函数调用都按预期执行(当我按下按钮时,QT槽buttonClicked()被调用,接着调用CLogic_buttonClicked(),计划中调用QTWidget::displayText()),但在最后一个调用中,参数是无效的。char *文本指向0x1,并声称指向越界的内存,而int位置看起来像是一些随机数(未初始化)。
如何将这些数据从C传递到CPP?
编辑@Luccas Matteis:
#ifdef __cplusplus
#include "QTWidget.h"

extern "C" {
#endif

struct RefToWidget{
#ifdef __cplusplus
    void (QTWidget::*displayLine)(char* text, int lineNumber);
#else
    void (*displayLine)(char* text, int lineNumber);
#endif
};

typedef struct RefToWidget RefToWidget;
#ifdef __cplusplus
}
#endif

如上所述,函数调用的行为表现正常,但数据未被“正确”传递(尽管当我看代码时,代码似乎有点奇怪... ;))


“displayText”函数指针的声明是什么样子的? - Luca Matteis
请看我的编辑以获取声明 ;) - Timo
3个回答

4
你的问题并不是将char *从C传递到C++,而是在C中调用C++函数。我假设CLogic.c被编译为C库?如果不是,请将其重命名为CLogic.cpp或使用编译器开关强制将其编译为C++,即使它具有C文件扩展名。
如果你想在C库/系统上使用C++ GUI,则需要使用适当的Model-View-Controller逻辑。这里,C++代码是View和Controller,而C代码是Model(根据你的描述)。你需要设置和获取模型数据,但模型永远不会像你正在尝试的那样调用View或Controller。
思考一下你真正想做什么。如果你只想在按下按钮时显示静态字符串,为什么要打扰调用CLogic.c?如果你想显示取决于CLogic实例状态的字符串,那么可以尝试如下操作:
void QTWidget::buttonClicked()
{
    char *display_text = this->clogic->get_button_click_text();
    ui.textItem->setText(display_text);
}

第一段非常准确 :) 我现在实际上拥有C库的源代码,因此我正在构建两个独立的项目,一个GUI-CPP项目(使用g++),另一个控制台-C项目(使用gcc)。这确实需要一些额外的#ifdef __cplusplus检查,但是以这种方式代码变得更加可读。此外,我认为关于模型-视图-控制器的评论也很有道理。谢谢! - Timo

1
我猜问题在于结构体持有一个成员函数指针。该成员函数可能期望第一个参数是'this'——它所指的对象。因此,在调试时看到的文本实际上是第二个参数。
“解决方案”可能是像“instance.rtw->displayText(instance.rtw,“Hello World”,1)”这样做,但不知道它是否具有可移植性等等。
编辑:明确说一下:上述“解决方案”只是尝试检查是否存在该问题。正如评论所说,这是一种可怕的黑客行为,甚至可能在同一编译器上都无法正常工作。

我认为这里的细节是正确的,但是提出的解决方案是一个可怕的黑客行为,可能非常危险。正如 Vlad 所说,它可能也不具备可移植性。 - AlastairG
如果这是问题的话,我确实会像Luca所说的那样期望编译器错误。但事实并非如此,就像我之前说的,在调试过程中,我注意到函数调用本身似乎按正确顺序发生。只有参数没有正确发送(在从C到CPP代码的点上)。 - Timo
你在 "struct RefToWidget" 中所做的是错误的。如果你明确指定要发送“指向函数的指针”,然后发送“非静态方法的指针”,你不能期望编译器会出现错误。它们不是同一件事情。 - vladmihaisima

0

我认为你不应该从C语言调用C++方法。通常情况下,你需要通过一个静态方法来解除指针参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接