c语言的#include和java的import的区别以及库调用

49次阅读

共计 1669 个字符,预计需要花费 5 分钟才能阅读完成。

#include 是个宏命令,在文件编译阶段,会先将 #include 展开,也就是说被#include 引用的文件会在源文件中展开。举例:有两个.c 源文件,一个是 my.c 还有一个是 main.c 假如 my.c 文件内容是:
void fun(int x){printf(“%d\n”,x);}
而 main.c 文件的内容是:
#include”my.c”
int main()
{
return 0;
}
那么编译之前的预处理步骤,就会把 #include 的内容在 main.c 中展开,则变成:
void fun(int x){printf(“%d\n”,x);}
int main()
{
return 0;
}
当然,一般来讲是 #include .h 文件,而不是.c 文件。然后编译器实际上是对新的内容进行编译处理。编译的步骤则是:编译步骤
而 java 的 import 是否也是将代码展开呢?答案是否定的。java 语言中,每一个类都必须要用包名. 类名的形式来描述。只给出类名是无法完全描述一个类的,比如我们要用 HashMap 这个类就需要写成这样:
java.util.HashMap map = new java.util.HashMap();
这样的话每个类的调用都要这么麻烦,要记住包名,这样很不利于写项目代码。java 作为一门先进的现代编程语言,它的开发者也想到了这个问题,于是使用 import 来指定包或者直接指定类的名字,这样就不需要每次都将类完全描述,使得开发者能够专注于软件开发而不是各种包的导入。有了 import 之后,代码就变成了这样:
import java.util.*;

HashMap map = new HashMap();

不像 c 中的 #include 直接展开,这样做实际上只是指定了要引用的类,而具体的被引用类的代码则在执行的时候才调入内存 (这个步骤是类加载器来实现的)。这样做的好处是编译(编译成.class 文件) 速度较快, 运行速度稍慢,而 c 语言的展开方式编译会非常慢,运行则很快。当然 c 语言中也有运行时将代码调入内存的技术,即动态连接技术。不过 c 语言的动态连接实在是麻烦,就好像是在现代社会中我要获得火种,非得钻木取火。而且动态连接的前提还得是有动态链接库才行,如果没有就得自己写一个,写完之后编译的命令 (编译成库文件和编译成可执行文件的命令) 还不不一样。有了库之后,就可以调用了,但是调用库又变成了一个无法理解的事情。比如调用 windows 下的 dll 动态链接库中的函数:
#include <windows.h>
#include <stdio.h>
typedef int (*Fun)(int,int);
int main()
{
HINSTANCE hDll;
Fun Add;
hDll=LoadLibrary(“myDll.dll”);
if (hDll==NULL)
{
printf(“%s”,”failed to load dll!\n”);
}
else
{
printf(“%s”,”succeeded in loading dll\n”);
Add=(Fun)GetProcAddress(hDll,”add”);
if (Add!=NULL)
{
printf(“%d\n”,Add(12,94));
}
}
FreeLibrary(hDll);

return 0;}

在这个动态库调用中,明明已经知道有个函数 add(int,int),还非得写一堆东西,上面的那个 typedef 是定义了一个函数指针,为了指向 add 这个函数,但是???what???开发人员调用库的目的就是为了简单,就是为了方便,就是为了好用,如果调库还需要这么麻烦,还需要定义什么指针,那还调库干嘛。
而 java 的动态连接则不存在这种问题,因为 java 的设计原则中只有库,class 文件就是库,而.jar 不过是一堆的.class 文件。在 java 编程中引用一个类实际上就进行了一次动态连接,并且这种动态连接却和调用本类一样方便,就比如自己写了一个 my.MyMap 类,在别的类里直接 new my.MyMap()就可以了,完全没有上面的那些步骤。当然能这么方便是得益于虚拟机中的类加载器。

正文完
 0