【问题标题】:error C2664 due to cdecl and myclass conflict由于 cdecl 和 myclass 冲突导致的错误 C2664
【发布时间】:2013-03-27 11:47:51
【问题描述】:

我正在尝试将 C 中的一段旧代码加入到我目前的 VC++ 项目中:

// .h
    class DMSinv : public CDialog {
        double finte(double z);
        double ITFStolz(double Zp1, double Zp2, double Zc);
    };

// .cpp
    double Zcglob;
    double DMSinv::finte(double z) 
    {
       return TFStolz(z, Zcglob);
    }

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
    {
        int ierr;
        Zcglob = Zc;

        return (coteglob(&DMSinv::finte, Zp1, Zp2, 1.0e-10, &ierr));
    //error C2664: 'DMSinv::coteglob' : cannot convert parameter 1 from 'double (__thiscall DMSinv::* )(double)' to 'double (__cdecl *)(double)'    

    }

coteglob 函数来自旧的 C 部分,finte 是一个将 TFStolz 函数传递给 coteglob 的中间函数。

我在论坛中搜索并发现了这个相关问题: How to convert void (__thiscall MyClass::* )(void *) to void (__cdecl *)(void *) pointer 我试图以这种方式申请:

// .h
    class DMSinv : public CDialog {
        virtual double finte(double z);
        double ITFStolz(double Zp1, double Zp2, double Zc);
    };

// .cpp
    double Zcglob;
    extern "C"
    {
        static double __cdecl finteHelper(double z)
        {
            DMSinv* datainv = reinterpret_cast< DMSinv > (z); //error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'DMSinv'  

            datainv->finte(z);
        }
    }

    double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
    {
        int ierr;
        Zcglob = Zc;
        double solution = coteglob(&finteHelper, Zp1, Zp2, 1.0e-10, &ierr);
        return solution;
    }

但仍然无法正常工作。有人可以指导我如何适应它吗?我还是个新手,这似乎与我的知识相去甚远。

提前致谢!

【问题讨论】:

  • DMSinv* datainv = reinterpret_cast&lt; DMSinv &gt; (z) - 你不应该投到DMSinv* 吗?
  • 我试过了,但同样的错误:error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'DMSinv*'

标签: class visual-c++ cdecl c2664


【解决方案1】:

不确定是否可以随心所欲。我想到的唯一选择是使用一些静态变量来存储 DMSinv 对象的地址。这将您限制为 1 个线程,实现简单...

试试这个:

// .h
class DMSinv : public CDialog {
    double finte(double z);
    double ITFStolz(double Zp1, double Zp2, double Zc);

private:
  static DMSinv* _current;
  static double __cdecl finteHelper(double z);
};

// .cpp
double Zcglob;
DMSinv* DMSinv::_current = 0;
double DMSinv::finte(double z) 
{
   return TFStolz(z, Zcglob);
}

double DMSinv::ITFStolz(double Zp1, double Zp2, double Zc)
{
    int ierr;
    Zcglob = Zc;

   _current = this;
   return (coteglob(DMSinv::finteHelper, Zp1, Zp2, 1.0e-10, &ierr));
}

double __cdecl DMSinv::finteHelper(double z)
{
    return _current->finte(z);
}

这不是 IMO 的好解决方案,但我不确定是否有其他方法。

附言 要消除一个线程的限制,您可以使用 TLS 插槽或在 VC++ 中仅使用 __declspec(thread)。 后者只需将__declspec(thread) 添加到_current,如下所示:static __declspec(thread) DMSinv* _current;。但!!!请注意,每个线程变量的数量对于进程是有限的。在 MSDN 中了解更多信息。

更新

免责声明:只是为了好玩。

理论上,还有其他机会。您可以将汇编代码存储在数组中,附加到对象。这个汇编代码应该是一个 __cdecl 函数,它根据 eip 寄存器简单地将 __cdecl 转换为 __thiscall。但这永远不应该这样做......:D

【讨论】:

  • 为什么它要求我在finiteHelper中返回一个值,当是静态时是否需要? error C4716: 'DMSinv::finteHelper' : must return a value。感谢__declspec(thread),看起来很有趣,我去看看。
  • 我已经更新了我的代码来修复这个错误。只需添加 return as,编译器会问你。
  • 好的,谢谢,现在它可以编译了,但没有运行,有时会中断。我会继续研究为什么会发生这种情况,正如您所说,这可能不是最好的解决方案,但感谢您的帮助!
  • 我再次更新了我的代码。看起来你刚刚在这里获得了 NULL 指针访问。将 _current 分配移至其他函数。不过要注意一点。如果对 coteglob 的调用是异步的(即它会在您的主线程运行一段时间后返回),您就会遇到麻烦。您需要等到此 coteglob 调用回调才能将finiteHelper 用于DMSinv 的其他实例。
  • 非常感谢denis-bu,感谢您的帮助和解释,使其更容易理解,这真的超出了我的范围,很抱歉延迟回答,我正在旅行
【解决方案2】:

我认为你不能这样做。您需要以某种方式将引用传递给您的对象 (this)。在链接的问题中,函数的参数被定义为类型void *,因此您可以将所需的任何内容传递给函数,包括指向this 的指针。您的函数接受double,因此您不能将this 传递给它。

我认为最简单的方法是在类外定义中间函数,因为它似乎独立于类内部。像这样的:

double finte(double z) 
{
   return TFStolz(z, Zcglob);
}

您还可以将实例指针存储在静态函数可以读取的公共全局/静态类内变量中。

【讨论】:

  • 这似乎是一个简单而干净的解决方案,但 TFStolz 是 DMSinv 类的一个函数,所以如果 finte 不在类中,它不会识别 TFStolz:error C3861: 'TFStolz': identifier not found。也许在finte中包含TFStolz的指针......我必须重新考虑它,因为我说我是一个新手并且不能轻松解决这个问题。谢谢!
猜你喜欢
  • 2014-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-06
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
  • 2018-08-30
相关资源
最近更新 更多