主题:想不明白问题在哪
azazaz
[专家分:30] 发布于 2008-02-24 14:02:00
今天做了一个小练习,可出现了一个想不明白的问题
题目是找出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个回复)
沙发
老大徒伤悲 [专家分:29120] 发布于 2008-02-24 15:02:00
如果只要vb,我也许可以看看。混编就……
板凳
老大徒伤悲 [专家分:29120] 发布于 2008-02-24 15:09:00
[quote]Form1上只有一个Combo控件[/quote]如此机械的问题,不要再vb中自己加任何控件,直接输出在窗体上就行了。
vb部分没有问题,建议仔细测试你的素数判定程序,我怀疑那里有问题。
3 楼
anbry [专家分:380] 发布于 2008-02-24 16:37:00
你这个问题出在生成的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 楼
华山论剑 [专家分:5310] 发布于 2008-02-25 09:53:00
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 楼
anbry [专家分:380] 发布于 2008-02-25 15:23:00
华山论剑说的“楼主既然用了#include<cmath>和cpp,系统会按C++编译而不用C,所以用bool是支持的”
这一点我不敢荀同。
经VC++2005,windows server 2003下编译。以bool类型返回是得不到正确值的。而以BOOL才能返回正确的结果。不知道你经过调试没?
而extern "C"的意思就是以C的形式来生成DLL。不管是CPP,还是C生成的都是一样的。
6 楼
anbry [专家分:380] 发布于 2008-02-25 15:38:00
差点忘记了,还有一点忘记说了。
华山论剑说“系统会按C++编译而不用C”
如果是这样的话,那
for(int i=2;i<=n-1;i++)
if(n%i==0) return false;
也是正确的。
但结果呢,经调试循环体根本一次也没有进入,你做何解释?
别在同一个CPP中进行调试,把以上代码生成DLL,再用VB进行调用。我就不信你能给我调得出来!!
7 楼
华山论剑 [专家分:5310] 发布于 2008-02-25 15:43:00
楼主上面已经指明是用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 楼
anbry [专家分:380] 发布于 2008-02-25 15:47:00
希望楼主早点看到,早点回复,我指出的错误如果不改,能不能调试通过?
改正后能不能通过。
至于程序效率问题华山论剑说的是对的。
9 楼
azazaz [专家分:30] 发布于 2008-02-28 19:19:00
呵呵,问题居然这么简单就解决,只要在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 楼
anbry [专家分:380] 发布于 2008-03-02 03:28:00
华山论剑,咱也别争了!!
代码对于不对主要的不是哪本书上说行不行,书上说的再对,但编译过不过了也是没用的。VC++6.0并不是完全标准的C++编译器。CPP文件只要在编译器的编译选项中调整下用C来编译,不管扩展名是什么都一样可以用。
举个简单的例子吧,我有一个“abc.bat”文件,我把名字改成“abc.txt”用cmd abc.txt一样可以运行这个批处理。
我来回复