静态连接库??

famugong 2000-08-30 10:18:00
小弟我最近找到一篇关于用户模块的文章,她的第一部分就讲到了静态连接库,还负了一个例子,很详细,正适合我这个初学者,于是就按他说的做,但运行发现有错,不知为何,请各位指点一二,一定要帮我一把啊,我已经给这些搞的快崩溃了.


以下是它的原文:
现在以一个简单的数学函数库为例介绍静态库的创建和使用。

要创建静态库,选择File->New菜单,弹出New对话框。选择Projects标签,在项目类型列表框中选择Win32 Static Library,在Name中输入mymath,表明要创建一个mymath.lib的静态库文件。

然后用Project->Add to Project->Files菜单往mymath工程中加入以下两个文件:

1.头文件(见清单9.1):定义了Summary和Factorial两个函数,分别用于完成求和与阶乘。注意这里使用C风格的函数,需要加入extern “C”关键字,表明它是C风格的外部函数。

清单9.1 头文件

#ifndef _MYMATH_H //////还有,请问这里为什么是_MYMATH_H,它是根据文件名
///// 来的吧,但为什么写陈这样呢?经常看到一些名字前加上
//// "_",有什么特殊意义吗?
#define _MYMATH_H

extern “C”

{

int Summary(int n);

int Factorial(int n);

}

#endif

2.源文件:包含了Summary和Factorial函数的定义,见清单9.2。

清单9.2 源文件

int Summary(int n)

{

int sum=0;

int i;

for(i=1;i<=n;i++)

{

sum+=i;

}

return sum;

}

int Factorial(int n)

{

int Fact=1;

int i;

for(i=1;i<=n;i++)

{

Fact=Fact*i;

}

return Fact;

}

 

在Build菜单下,选择Build菜单下的Build mymath.lib。Visual C++编译链接工程,在mymath\debug目录下生成mymath.lib文件。至此,静态连接库生成的工作就做完了。下面用一个小程序来测试这个静态库。

提示:用户在交付最终静态连接库时,只需要提供.lib文件和头文件,不需要再提供库的源代码。

 

9.2.2测试静态库

 

用AppWizard生成一个基于对话框的应用程序test。打开test资源文件,修改IDD_TEST_DIALOG对话框资源,加入两个按钮。按钮ID和文字为:

IDC_SUM “&Summary”

IDC_FACTORIAL “&Factorial”

如图9-1所示。



图9-1 修改test对话框

用ClassWizard为上述两个按钮Click事件生成消息处理函数OnSum和OnFactorial,并加入代码,修改后的OnSum和OnFactorial见清单9.3。

清单9.3 OnSum和OnFactorial函数定义

void CTestDlg::OnSum()

{

// TODO: Add your control notification handler code here

int nSum=Summary(10);

CString sResult;

sResult.Format("Sum(10)=%d",nSum);

AfxMessageBox(sResult);

}

void CTestDlg::OnFactorial()

{

// TODO: Add your control notification handler code here

int nFact=Factorial(10);

CString sResult;

sResult.Format("10!=%d",nFact);

AfxMessageBox(sResult);

}

由于要使用mymath.lib中的函数,首先要将mymath.lib和mymath.h两个文件拷贝到test目录下。然后用Project->Add to Project->Files命令,将mymath.lib加入到工程中。

在testdlg.cpp文件头部,还要加入头文件mymath.h:

#include "stdafx.h"

#include "Test.h"

#include "TestDlg.h"

 

#include "mymath.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

编译运行test程序,点Factorial按钮,弹出如图9-2的消息框。



图9-2 Test程序运行结果



运行后在linking时发生错误:unrevoled external symbol _Summary
unrevoled external symbol _Factorial


...全文
258 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
UltraUnAsm 2000-09-04
  • 打赏
  • 举报
回复
客气了!
你要的东西是MicroSoft的,在MSDN上应该有。
UltraUnAsm 2000-09-04
  • 打赏
  • 举报
回复
太客气了。
你要的东西既然是MicroSoft的,在MSDN上应该有。
LiangFomu 2000-09-01
  • 打赏
  • 举报
回复
在project的setting中的Link\general下的Object/Library modules:加入库文件eg:d:\MyLibrarys\mymath.lib
famugong 2000-09-01
  • 打赏
  • 举报
回复
哦,我明白了,原来是这样.
要学的还真不少.
谢谢,very much!
顺便问一下:__stdcall , __fastcall这些是什么,能不能讲解一下,或者哪里有这方面的资料呢.
再次感谢!
(好像不能给分了吧,我也没多少可给了:-p)
UltraUnAsm 2000-09-01
  • 打赏
  • 举报
回复
famugong:
你可能完全搞错了。
真正的问题可能是:
Summary和Factorial被定义在.CPP文件中而不是在.C文件中!

问题不在于.h文件。nitrogen的.h写法:
#ifdef _cplusplus
extern "C"
{
#endif
....
....
#ifdef _cplusplus
}
#endif
相对更标准。保证只在被.cpp文件include时使用extern "C"。原来的写法被.c文件include时编译器会报非法。


出问题的地方是.cpp文件内定义的函数的名称被编译器以C++的name mangling改变(主要是为了支持重载)后放入.obj(或.lib ...)文件。name mangling每家编译器做法都不同,甚至同一家编译器不同版本处理方式也不一样。而C格式是有统一标准的(标准是前面加下划线,VC++还有__stdcall , __fastcall做法(如果你在声明时指明,)),用汇编做过C库的人知道。
去掉.h文件中的extern "C"将导致你的lib只能被VC++(甚至可能只是那个版本使用),我想你并不希望这样。所以除非你会让编译器以C方式编译.cpp文件,简单的方法是把.cpp文件名改为.c文件名。这样BCB也可以使用你的lib了(只要它认lib的二进制格式)。另外,在定义文件开头include声明文件(.h) 较好(有时是必须的,在你的例子中假如summary 有call Factorial的话)。
这个问题和WINDOWS ,WIN32完全无关。
nitrogen 2000-08-31
  • 打赏
  • 举报
回复
比较标准的的写法是这样的:
#ifdef _cplusplus
extern "C"
{
#endif
....
....
#ifdef _cplusplus
}
#endif
这样的话, 你生成的库就既可以用在C中,又可以用在C++中了. 这和是否win32没有任何关系的,
extern "C"是C/C++的语法, 本义就是为了C/C++混合编程用的.
你原来的链接错误可能是因为生成的mymath.lib中的符号是C++方式的, 而使用库的程序却要求用
C方式找到符号, 于是出现"unrevoled external symbol".
你可以使用VC的工具dumpbin mymath.lib看一下mymatch.lib的符号表, 验证一下
U皮特U 2000-08-31
  • 打赏
  • 举报
回复
我仅在调用用汇编写的函数时才要在函数定义中加上extern "C"修饰,你的这两个函数完全是按照Win32编译的,自然不需要。
这个警告是由于试图链接两个矛盾的运行库。libcd.lib是单线程调试版的运行库,与libc.lib,libcmt.lib,msvcrt.lib,libcmtd.lib,msvctd.lib相矛盾。试试以下的方法:
在链接选项中加入:
/NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvctd.lib
不过我觉得这种警告可以忽略。
famugong 2000-08-31
  • 打赏
  • 举报
回复
nitrogen:thank you,but Summary和factorial是定义在.cpp中的.
softsprite:thank you 我按照你说的去掉了extern "c",运行无错误,但是出现了warning:
LINK : warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library
这是怎么一回事?
还有,为什么去掉就对了呢?能不能解释以下.
nitrogen 2000-08-30
  • 打赏
  • 举报
回复
extern "C"应该加上的, Summary和Factorial两个函数的定义很可能在某个.c中, 这样生成的
mymath.lib中这两个函数的内部命名方式是C方式的, 但是使用库的是.cpp文件, 这样在调用mymath.lib中的函数时, .cpp生成的目标文件将引用c++命名风格的Summary和Factorial函数, 会造成连接失败.
U皮特U 2000-08-30
  • 打赏
  • 举报
回复
1. 将mymath.h中的extern "C" { 和 }这两行删除即可。
原因是你建立的是win32 lib,两个函数也是标准的C++函数,没有什么特别的C风格。

2.
#ifndef _MYMATH_H
#define _MYMATH_H
...
#endif

这种用法在头文件中很常用,目的是防止头文件被多次包含。_MYMATH_H这个宏确实是根据文件名来的,即保证唯一性又好记,不必费心去想用什么唯一的标识符。其实你可以用任意的字符串,只要在全项目中是唯一的即可。VC本身自动生成的类的头文件中都有类似AFX_TESTDLG_H__50D9516E_7ECA_11D4_98A4_0000E840B56C__INCLUDED_之类的标识符,用处是一样的,它可以通过计算自动生成唯一的字符串,人脑不如电脑,简单地使用文件名即可基本保证唯一性了。
"_"是VC中内部的风格,一般自定义的变量开头不会用"_",以示区别。
nitrogen 2000-08-30
  • 打赏
  • 举报
回复
加上
#ifndef _MYMATH_H
#define _MYMATH_H
#endif
的意思是为了防止头文件重复包含, 如果你包含了这个头文件多次的话, 第一次包含时宏_MYMATH_H还没有定义, 于是编译器在预处理过程中定义宏_MYMATH_H, 并包含
"#define _MYMATH_H"和"#endif"之间的代码到你的程序中, 如果你包含第二次的话, 由于宏
_MYMATH_H已经定义, 头文件中的内容将不被处理. 至于宏的名字可以是任意的, 但根据文件名来命名简单且不容易重复, 是比较流行的方式

famugong 2000-08-30
  • 打赏
  • 举报
回复
什么意思?
请你详细点.
Areslee 2000-08-30
  • 打赏
  • 举报
回复
在TEST的连接时没有加入你编的库文件

16,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧