回 帖 发 新 帖 刷新版面

主题:想不明白问题在哪

今天做了一个小练习,可出现了一个想不明白的问题

题目是找出100到999之间的既是回文数且又素数的数,目标是练习VB和C++的混编

判断一个数是否是回文数,素数的函数用C++编:

1.cpp:

#include<cmath>

extern "C" __declspec(dllexport) bool __stdcall prime(int n)
{
    for(int i=2;i<=n-1;i++)
        if(n%i==0) return false;
    return true;
}

extern "C" __declspec(dllexport) bool __stdcall huiwen(int n)
{
    int t=n,m=0;
    while(t)
    {
        m=m*10+t%10;
        t/=10;
    }
    return(m==n);
}


1.def:

LIBRARY 1
EXPORTS
 
 prime @1
 huiwen @2

以上使用VC++ 6.0编译成1.dll


VB部分:
Form1上只有一个Combo控件

Private Declare Function huiwen Lib "1.dll" (ByVal n As Long) As Boolean
Private Declare Function prime Lib "1.dll" (ByVal n As Long) As Boolean

Private Sub Form_Load()
Me.Show
Combo1.Clear
Dim i As Long
For i = 100 To 999
If (prime(i) And huiwen(i)) Then Combo1.AddItem i
Next
End Sub

经我测试,用C++编的两个函数应该没问题,因为我建了一个C++ Win32 Console工程,编了一个main()函数测试,没有问题,但上面的程序100-500之间的数是算对了,可600以上的数就有问题了,连969,999都加到了Combo1里,我又将循环改成For i=10 To 99 算得结果又是正确的.

问题到底在哪呢

回复列表 (共11个回复)

沙发

如果只要vb,我也许可以看看。混编就……

板凳

[quote]Form1上只有一个Combo控件[/quote]如此机械的问题,不要再vb中自己加任何控件,直接输出在窗体上就行了。
vb部分没有问题,建议仔细测试你的素数判定程序,我怀疑那里有问题。

3 楼

你这个问题出在生成的DLL上。
1、你的函数头是extern "C" __declspec(dllexport) bool __stdcall prime(int n)
   这样声明的,也就是说以C的代码进行生成,在C语言中是不支持bool类型的,可以改成BOOL或者是int类型。
2、for(int i=2;i<=n-1;i++),这个语句看清楚了,你是生成C的代码,在C中这样声明i变量是错误的。在C++可以这样声明。
改正后的代码如下:
#include<cmath>

extern "C" __declspec(dllexport) BOOL __stdcall prime(int n)
{
    int i;
    for(i=2;i<=n-1;i++)
    {
        if(n%i==0)
            return 0;
    }
    return 1;
}

extern "C" __declspec(dllexport) BOOL __stdcall huiwen(int n)
{
    int t=n,m=0;
    while(t)
    {
        m=m*10+t%10;
        t/=10;
    }
    return(m==n);
}


以上代码在windows server 2003 + VS2005 + VB6.0下调试通过。

4 楼

1、楼主既然用了#include<cmath>和cpp,系统会按C++编译而不用C,所以用bool是支持的;

2、你的程序效率太低:
[code=c]
   for(int i=2;i<=n-1;i++)
        if(n%i==0) return false;
[/code]
   判断素数根本不用循环到n-1,循环到n的平方根加1就行了,修改为:
[code=c]
    int max = (int)sqrt(n) + 1;
    for (int i=2; i<=max; i++)
        if (n%i==0)
            return false;
[/code]
   这样,速度提高10倍以上;

3、另一个效率问题。要判断回文,且条件是100到999,只需要判断前1位等于后一位就行了,所以只需要一句:

    return (n % 10 == n / 100);        

4、第3个效率问题。

   If (prime(i) And huiwen(i)) 

   因为回文的判断简单得多,所以应该将回文判断放前面,对于And来说,在C/C++中,第1个为假第2个就不执行了,VB中我却没有明确实验过。

所以简单的两个判断,1个函数就足够了。下面给出参考:

extern "C" __declspec(dllexport) bool __stdcall IsNumOK(int n)
{
    if (n % 10 != n / 100)
        return false;

    int max = (int)sqrt(n) + 1;
    for (int i=2; i<=max; i++)
        if (n%i==0)
            return false;

    return true;
}

5 楼

华山论剑说的“楼主既然用了#include<cmath>和cpp,系统会按C++编译而不用C,所以用bool是支持的”

这一点我不敢荀同。

经VC++2005,windows server 2003下编译。以bool类型返回是得不到正确值的。而以BOOL才能返回正确的结果。不知道你经过调试没?

而extern "C"的意思就是以C的形式来生成DLL。不管是CPP,还是C生成的都是一样的。



6 楼

差点忘记了,还有一点忘记说了。

华山论剑说“系统会按C++编译而不用C”

如果是这样的话,那
for(int i=2;i<=n-1;i++)
        if(n%i==0) return false;
也是正确的。

但结果呢,经调试循环体根本一次也没有进入,你做何解释?

别在同一个CPP中进行调试,把以上代码生成DLL,再用VB进行调用。我就不信你能给我调得出来!!

7 楼

楼主上面已经指明是用VC++6.0编译的,6.0下只要后缀是cpp,就会照C++编译,是可以编译通过的,楼主的问题也不是出在bool上。

extern "C"不只是针对C语言的,C++语言也一样用,它的作用不是按什么语言编译,而是C和C++之间相互调用的指示,在C++中增加extern "C"(不是"C++")表示C++函数可以为C语言调用,详细的可以参考"C++ Primer" 7.7章。

8 楼

希望楼主早点看到,早点回复,我指出的错误如果不改,能不能调试通过?

改正后能不能通过。

至于程序效率问题华山论剑说的是对的。

9 楼

呵呵,问题居然这么简单就解决,只要在C++中将函数头改成int型的就完全正确了:

#include<cmath>

extern "C" __declspec(dllexport) int __stdcall prime(int n)
{
    int i;
    for(i=2;i<=sqrt(n);i++)
        if(n%i==0) return 0;
    return 1;
}

extern "C" __declspec(dllexport) int __stdcall huiwen(int n)
{
    int t=n,m=0;
    while(t)
    {
        m=m*10+t%10;
        t/=10;
    }
    return(m==n);
}

以后混编我也尽量不用bool型

谢谢各位了

10 楼

华山论剑,咱也别争了!!

代码对于不对主要的不是哪本书上说行不行,书上说的再对,但编译过不过了也是没用的。VC++6.0并不是完全标准的C++编译器。CPP文件只要在编译器的编译选项中调整下用C来编译,不管扩展名是什么都一样可以用。

举个简单的例子吧,我有一个“abc.bat”文件,我把名字改成“abc.txt”用cmd abc.txt一样可以运行这个批处理。

我来回复

您尚未登录,请登录后再回复。点此登录或注册