<<软件工程师的自小弟我修养>>第266页异常是不是有误
<<程序员的自我修养>>第266页错误是不是有误?
最近闲来无事,就又看了下<<程序员的自我修养>>,发现,书中所写与实践不符
到底是我错,还是书错?
书中写道:
"编译器在产生导入库,同一个导出函数会产生两个符号定义,比如函数foo来说,它在导入库有两个符号,一个是foo,另外一个是__imp__foo "
可我实际命令查看了一下,这两个符号是一个是_foo,另外一个是__imp__foo .
测试过程如下:
1.文件mydll.c内容
__declspec(dllexport) double foo(double a,double b)
{
return a+b;
}
2.编译: cl /LDd mydll.c
产生mydll.lib mydll.cll
3.查看mydll.lib的所有内容:
dumpbin /ALL mydll.lib
输出:
..........略...............
5 public symbols
16E __IMPORT_DESCRIPTOR_mydll
390 __NULL_IMPORT_DESCRIPTOR
4C4 mydll_NULL_THUNK_DATA
612 __imp__foo
612 _foo
..........略...............
不知,我的分析到底对不对,大牛指教
------解决方案--------------------
这里算是个错误吧,Windows默认情况下这里确实应该是_foo,具体可以看看这一节:
------解决方案--------------------
3.5.3 符号修饰与函数签名(1)
约在20世纪70年代以前,编译器编译源代码产生目标文件时,符号名与相应的变量和函数的名字是一样的。比如一个汇编源代码里面包含了一个函数foo,那么汇编器将它编译成目标文件以后,foo在目标文件中的相对应的符号名也是foo。当后来UNIX平台和C语言发明时,已经存在了相当多的使用汇编编写的库和目标文件。这样就产生了一个问题,那就是如果一个C程序要使用这些库的话,C语言中不可以使用这些库中定义的函数和变量的名字作为符号名,否则将会跟现有的目标文件冲突。比如有个用汇编编写的库中定义了一个函数叫做main,那么我们在C语言里面就不可以再定义一个main函数或变量了。同样的道理,如果一个C语言的目标文件要用到一个使用Fortran语言编写的目标文件,我们也必须防止它们的名称冲突。
为了防止类似的符号名冲突,UNIX下的C语言就规定,C语言源代码文件中的所有全局的变量和函数经过编译以后,相对应的符号名前加上下划线"_"。而Fortran语言的源代码经过编译以后,所有的符号名前加上"_",后面也加上"_"。比如一个C语言函数"foo",那么它编译后的符号名就是"_foo";如果是Fortran语言,就是"_foo_"。
这种简单而原始的方法的确能够暂时减少多种语言目标文件之间的符号冲突的概率,但还是没有从根本上解决符号冲突的问题。比如同一种语言编写的目标文件还有可能会产生符号冲突,当程序很大时,不同的模块由多个部门(个人)开发,它们之间的命名规范如果不严格,则有可能导致冲突。于是像C++这样的后来设计的语言开始考虑到了这个问题,增加了名称空间(Namespace)的方法来解决多模块的符号冲突问题。
但是随着时间的推移,很多操作系统和编译器被完全重写了好几遍,比如UNIX也分化成了很多种,整个环境发生了很大的变化,上面所提到的跟Fortran和古老的汇编库的符号冲突问题已经不是那么明显了。在现在的Linux下的GCC编译器中,默认情况下已经去掉了在C语言符号前加"_"的这种方式;但是Windows平台下的编译器还保持的这样的传统,比如Visual C++编译器就会在C语言符号前加"_",GCC在Windows平台下的版本(cygwin、mingw)也会加"_"。GCC编译器也可以通过参数选项"-fleading-underscore"或"-fno-leading-underscore"来打开和关闭是否在C语言符号前加上下划线。
------解决方案--------------------

太专业
------解决方案--------------------
cdecl stdcall也会影响符号名字的
------解决方案--------------------
1# 已经回答了这个问题,显灵了你也看不见
------解决方案--------------------
最近闲来无事,就又看了下<<程序员的自我修养>>,发现,书中所写与实践不符
到底是我错,还是书错?
书中写道:
"编译器在产生导入库,同一个导出函数会产生两个符号定义,比如函数foo来说,它在导入库有两个符号,一个是foo,另外一个是__imp__foo "
可我实际命令查看了一下,这两个符号是一个是_foo,另外一个是__imp__foo .
测试过程如下:
1.文件mydll.c内容
__declspec(dllexport) double foo(double a,double b)
{
return a+b;
}
2.编译: cl /LDd mydll.c
产生mydll.lib mydll.cll
3.查看mydll.lib的所有内容:
dumpbin /ALL mydll.lib
输出:
..........略...............
5 public symbols
16E __IMPORT_DESCRIPTOR_mydll
390 __NULL_IMPORT_DESCRIPTOR
4C4 mydll_NULL_THUNK_DATA
612 __imp__foo
612 _foo
..........略...............
不知,我的分析到底对不对,大牛指教
------解决方案--------------------
这里算是个错误吧,Windows默认情况下这里确实应该是_foo,具体可以看看这一节:
3.5.3 符号修饰与函数签名(1)
约在20世纪70年代以前,编译器编译源代码产生目标文件时,符号名与相应的变量和函数的名字是一样的。比如一个汇编源代码里面包含了一个函数foo,那么汇编器将它编译成目标文件以后,foo在目标文件中的相对应的符号名也是foo。当后来UNIX平台和C语言发明时,已经存在了相当多的使用汇编编写的库和目标文件。这样就产生了一个问题,那就是如果一个C程序要使用这些库的话,C语言中不可以使用这些库中定义的函数和变量的名字作为符号名,否则将会跟现有的目标文件冲突。比如有个用汇编编写的库中定义了一个函数叫做main,那么我们在C语言里面就不可以再定义一个main函数或变量了。同样的道理,如果一个C语言的目标文件要用到一个使用Fortran语言编写的目标文件,我们也必须防止它们的名称冲突。
为了防止类似的符号名冲突,UNIX下的C语言就规定,C语言源代码文件中的所有全局的变量和函数经过编译以后,相对应的符号名前加上下划线"_"。而Fortran语言的源代码经过编译以后,所有的符号名前加上"_",后面也加上"_"。比如一个C语言函数"foo",那么它编译后的符号名就是"_foo";如果是Fortran语言,就是"_foo_"。
这种简单而原始的方法的确能够暂时减少多种语言目标文件之间的符号冲突的概率,但还是没有从根本上解决符号冲突的问题。比如同一种语言编写的目标文件还有可能会产生符号冲突,当程序很大时,不同的模块由多个部门(个人)开发,它们之间的命名规范如果不严格,则有可能导致冲突。于是像C++这样的后来设计的语言开始考虑到了这个问题,增加了名称空间(Namespace)的方法来解决多模块的符号冲突问题。
但是随着时间的推移,很多操作系统和编译器被完全重写了好几遍,比如UNIX也分化成了很多种,整个环境发生了很大的变化,上面所提到的跟Fortran和古老的汇编库的符号冲突问题已经不是那么明显了。在现在的Linux下的GCC编译器中,默认情况下已经去掉了在C语言符号前加"_"的这种方式;但是Windows平台下的编译器还保持的这样的传统,比如Visual C++编译器就会在C语言符号前加"_",GCC在Windows平台下的版本(cygwin、mingw)也会加"_"。GCC编译器也可以通过参数选项"-fleading-underscore"或"-fno-leading-underscore"来打开和关闭是否在C语言符号前加上下划线。
------解决方案--------------------
3.5.3 符号修饰与函数签名(1)
约在20世纪70年代以前,编译器编译源代码产生目标文件时,符号名与相应的变量和函数的名字是一样的。比如一个汇编源代码里面包含了一个函数foo,那么汇编器将它编译成目标文件以后,foo在目标文件中的相对应的符号名也是foo。当后来UNIX平台和C语言发明时,已经存在了相当多的使用汇编编写的库和目标文件。这样就产生了一个问题,那就是如果一个C程序要使用这些库的话,C语言中不可以使用这些库中定义的函数和变量的名字作为符号名,否则将会跟现有的目标文件冲突。比如有个用汇编编写的库中定义了一个函数叫做main,那么我们在C语言里面就不可以再定义一个main函数或变量了。同样的道理,如果一个C语言的目标文件要用到一个使用Fortran语言编写的目标文件,我们也必须防止它们的名称冲突。
为了防止类似的符号名冲突,UNIX下的C语言就规定,C语言源代码文件中的所有全局的变量和函数经过编译以后,相对应的符号名前加上下划线"_"。而Fortran语言的源代码经过编译以后,所有的符号名前加上"_",后面也加上"_"。比如一个C语言函数"foo",那么它编译后的符号名就是"_foo";如果是Fortran语言,就是"_foo_"。
这种简单而原始的方法的确能够暂时减少多种语言目标文件之间的符号冲突的概率,但还是没有从根本上解决符号冲突的问题。比如同一种语言编写的目标文件还有可能会产生符号冲突,当程序很大时,不同的模块由多个部门(个人)开发,它们之间的命名规范如果不严格,则有可能导致冲突。于是像C++这样的后来设计的语言开始考虑到了这个问题,增加了名称空间(Namespace)的方法来解决多模块的符号冲突问题。
但是随着时间的推移,很多操作系统和编译器被完全重写了好几遍,比如UNIX也分化成了很多种,整个环境发生了很大的变化,上面所提到的跟Fortran和古老的汇编库的符号冲突问题已经不是那么明显了。在现在的Linux下的GCC编译器中,默认情况下已经去掉了在C语言符号前加"_"的这种方式;但是Windows平台下的编译器还保持的这样的传统,比如Visual C++编译器就会在C语言符号前加"_",GCC在Windows平台下的版本(cygwin、mingw)也会加"_"。GCC编译器也可以通过参数选项"-fleading-underscore"或"-fno-leading-underscore"来打开和关闭是否在C语言符号前加上下划线。
------解决方案--------------------
太专业
------解决方案--------------------
cdecl stdcall也会影响符号名字的
------解决方案--------------------
1# 已经回答了这个问题,显灵了你也看不见
------解决方案--------------------
dll 导出函数名的那些事
关键字: VC++ DLL 导出函数
经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。
VC++支持两种语言:即C/C++,这也是造成DLL导出函数差异的根源
我们用VS2008新建个DLL工程,工程名为"TestDLL"
把默认的源文件后缀 .CPP改为.C(C文件)
输入测试代码如下:
01 int _stdcall MyFunction(int iVariant)
02 {
03 return 0;
04 }
为了导出上面这个函数,我们有以下几个方法:
1. 使用传统的模块定义文件 (.def)
新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为:
LIBRARY TestDll
EXPORTS
MyFunction
在 Link 时指定输入依赖文件:/DEF:"TestDll.Def"
2. Visual C++ 提供的方便方法
在01行的int 前加入 __declspec(dllexport) 关键字
通过以上两种方法,我们就可以导出MyFunction函数。
我们用Dependency查看导出的函数:
第一种方法导出的函数为:
MyFunction
第二种方法导出的函数为:
_MyFunction@4
__stdcall会使导出函数名字前面加一个下划线,后面加一个@再加上参数的字节数,比如_MyFunction@4的参数(int iVariant)就是4个字节
__fastcall与 __stdcall类似,不过前面没有下划线,而是一个@,比如@MyFunction@4
__cdecl则是始函数名。
小结:如果要导出C文件中的函数,并且不让编译器改动函数名,用def文件导出函数。
下面我们来看一下C++文件
我们用VS2008新建个DLL工程,工程名为"TestDLL"
默认的源文件后缀为 .CPP (即C++文件)。
输入测试代码如下:
01 int _stdcall MyFunction(int iVariant)
02 {
03 return 0;
04 }
为了导出上面这个函数,我们有以下几个方法:
3. 使用传统的模块定义文件 (.def)
新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为:
LIBRARY TestDll
EXPORTS
MyFunction
在 Link 时指定输入依赖文件:/DEF:"TestDll.Def"
4. Visual C++ 提供的方便方法
在01行的int 前加入 __declspec(dllexport) 关键字
通过以上两种方法,我们就可以导出MyFunction函数。
我们用Dependency查看导出的函数: