调用另一个文件中的函数在C相同的目录 [英] Calling a function from another file in the same directory in C

查看:137
本文介绍了调用另一个文件中的函数在C相同的目录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我学习C,但我有更高层次的编程语言的长期经验。

I'm learning C, but i have a long experience with higher level programming languages.

我正在阅读有关的头文件,所以我被他们玩弄,但我注意到,我可以打电话给另一个文件中的函数,而不#包括(但它是在同一目录下),怎么可能呢?! (我是Java程序员)
它是make文件,链接器被配置这种方式还是什么?
我用开发的cpp

I was reading about header files so i was playing around with them, however I noticed that I could call a function from another file without #including it (but it's in the same directory), how is that possible ?! (I'm java programmer) Is it the make file, linker that is configured that way or what ? I use Dev-Cpp

我们有两个文件

main.c
add.c

main.c中调用该函数添加(INT X,int y)对从添加add.c,但我#包括add.c之前错误地编译和它的工作!是什么使得它更糟糕的是,当我#包括add.c,它给在功能多定义错误添加

main.c calls the function add(int x,int y) from add add.c, but I mistakenly compiled before #including add.c and it worked ! What makes it worse, is that when i #include add.c, it gives a multiple-definition error on function add

推荐答案

有一些不同的东西怎么回事。首先,我将说明如何多个文件基本的编译工作。

There's a few different things going on here. First I'll go over how basic compilation of multiple files works.

如果您有多个文件,最重要的事情是函数的声明和定义的区别。该定义可能是你用来定义函数时是什么:你写上去的功能,内容像

If you have multiple files, the important thing is the difference between the declaration and definition of a function. The definition is probably what you are used to when defining functions: You write up the contents of the function, like

int square(int i) {
    return i*i;
}

声明,在另一方面,让你申报你知道一个函数存在的编译器,但你不要告诉编译器它是什么。例如,你可以写

The declaration, on the other hand, lets you declare to the compiler that you know a function exists, but you don't tell the compiler what it is. For example, you could write

int square(int i);

和编译器会期望的功能广场在别处定义。

And the compiler would expect that the function "square" is defined elsewhere.

现在,如果你有要互操作两个不同的文件(例如,让我们说,功能广场在add.c的定义,并要拨打main.c中广场(10))你需要做的两个的定义和声明。首先,您可以定义add.c.广场然后,您的声明的它在main.c中的开始这让编译器知道什么时候被编译main.c有它在其他地方定义的函数广场。现在,你需要编译双方的main.c和add.c成目标文件。您可以通过调用做到这一点。

Now, if you have two different files that you want to interoperate (for example, let's say that the function "square" is defined in add.c, and you want to call square(10) in main.c), you need to do both a definition and a declaration. First, you define square in add.c. Then, you declare it at the beginning of main.c. This let's the compiler know when it is compiling main.c that there is a function "square" which is defined elsewhere. Now, you need to compile both main.c and add.c into object files. You can do this by calling

gcc -c main.c
gcc -c add.c

这将产生文件main.o中和add.o.它们包含的编译函数,但不太可执行文件。在这里了解重要的是,main.o中在某种意义上是不完整。当编译main.o中,你告诉它的功能广场的存在,但功能广场是不是里面main.o.定义因此main.o中有一种晃来晃去参考的功能,广场的。除非你与它包含的方的​​定义,另一个的.o(或一个.so或.a)中的文件结合起来它不会编译成一个完整的程序。如果你只是尝试的链接的main.o中到一个程序,即

This will produce the files main.o and add.o. They contain the compiled functions, but are not quite executable. The important thing to understand here is that main.o is "incomplete" in a sense. When compiling main.o, you told it that the function "square" exists, but the function "square" is not defined inside main.o. Thus main.o has a sort of "dangling reference" to the function "square". It won't compile into a full program unless you combine it with another .o (or a .so or .a) file which contains a definition of "square". If you just try to link main.o into a program, i.e.

gcc -o executable main.o

您会得到一个错误,因为编译器会尽量的决心的悬空参考函数广场,但不会找到它的任何定义。但是,如果链接时包括add.o(链接是的解决方法的所有这些引用未定义的功能,而文件转换到的.o可执行文件或.so文件),那么就不会有任何问题。即。

You will get an error, because the compiler will try to resolve the dangling reference to the function "square", but wont find any definition for it. However, if you include add.o when linking (linking is the process of resolving all these references to undefined functions while converting .o files to executables or .so files), then there won't be any problem. i.e.

gcc -o executable main.o add.o

所以这是如何的功能的整个C文件使用的功能,但的文体的,就是我刚才给你是不正确的方式。我做的唯一原因是因为我认为这将更好地帮助您了解正在发生的事情,而不是依靠的#include神奇。现在,你可能已经注意到之前,事情变得有些混乱,如果你要重新定义你想在main.c中的顶部这就是为什么常常C程序使用所谓的头,它有一个.h扩展名助手文件使用每个功能。一个头的想法是,它包含的只是的功能,的没有的其定义的声明。这样一来,为了编译使用add.c定义函数的程序,您不必手动声明你正在使用每一个功能,也不需要你#包括整个add.c文件中的code。相反,你可以#包括add.h,它只是包含add.c.的所有功能中的声明

So that's how to functionally use functions across C files, but stylistically, what I just showed you is "not the right way". The only reason I did is because I think it will better help you understand what's going on, rather than relying on "#include magic". Now, you might have noticed before that things get a little messy if you have to redeclare every function you want to use at the top of main.c This is why often C programs use helper files called "headers" which have a .h extension. The idea of a header is that it contains just the declarations of the functions, without their definitions. This way, in order to compile a program using functions defined in add.c, you need not manually declare every function you are using, nor need you #include the entire add.c file in your code. Instead, you can #include add.h, which simply contains the declarations of all the functions of add.c.

现在,在#包括复习:#包括简单的直接拷贝一个文件的内容到另一个。因此,例如,code

Now, a refresher on #include: #include simply copies the contents of one file directly into another. So, for example, the code

abc
#include "wtf.txt"
def

完全等同于

abc
hello world
def

假设wtf.txt包含文本Hello World。

assuming that wtf.txt contains the text "hello world".

所以,如果我们把add.c的全部定义add.h(即

So, if we put all the definitions of add.c in add.h (i.e.

int square(int i);

和随后在main.c中的顶部,我们写

and then at the top of main.c, we write

#include "add.h"

这是功能一样的,如果我们刚刚宣布手动功能广场在main.c中的顶部。

This is functionally the same as if we had just manually declared the function "square" at the top of main.c.

因此​​,使用头文件的总体思路是,你可以有一个特殊的文件,它会自动声明需要通过只是#包括它的所有功能。

So the general idea of using headers is that you can have a special file that automatically declares all the functions you need by just #including it.

不过,包头也有一个比较常见的用途。让我们假设main.c中来自50个不同的文件使用的功能。 main.c中的顶部看起来像:

However, headers also have one more common use. Let's suppose that main.c uses functions from 50 different files. The top of main.c would look like:

#include "add.h"
#include "divide.h"
#include "multiply.h"
#include "eat-pie.h"
...

相反,人们常常将所有这些#包括到main.h头文件,并从main.c中只#包括main.h在这种情况下,头文件提供的两个的目的。被其他文件包含当它声明main.c中使用的功能,的它包括所有的main.c的依赖从main.c中包括时依赖使用这种方式也使的的。如果您#包括add.h,你不仅得到add.c定义的函数,但你也隐含其中获得使用add.c任何功能,任何功能的 <他们/ em>的使用,等等

Instead, people often move all those #includes to the main.h header file, and just #include main.h from main.c. In this case, the header file serves two purposes. It declares the functions in main.c for use when included by other files, and it includes all of the dependencies of main.c when included from main.c. Using it this way also allows chains of dependencies. If you #include add.h, not only do you get the functions defined in add.c, but you also implicitly get any functions which add.c uses, and any functions they use, and so on.

此外,更巧妙地从#包括它自己的.c文件的头文件隐式检查你犯错误。例如,如果你不小心定义广场为

Also, more subtly, #including a header file from it's own .c file implicitly checks for errors you make. If for example, you accidentally defined square as

double square(int i);

在add.h,你平时可能没有意识到,直到你被链接的main.o中正在寻找的有一个的平方的定义,add.o正在提供的另外,不兼容之一。这将导致你得到链接时的错误,这样你就不会意识到这个错误,直到后来在构建过程。但是,如果从add.c#包括add.h,编译器,你的文件看起来像

in add.h, you normally might not realize until you were linking that main.o is looking for one definition of square, and add.o is providing another, incompatible one. This will cause you to get errors when linking, so you won't realize the mistake until later in the build process. However, if you #include add.h from add.c, to the compiler, your file looks like

#include "add.h"
int square(int i) {
    return i*i;
}

该处理的#include语句之后的样子

which after processing the #include statement will look like

double square(int i);
int square(int i) {
    return i*i;
}

哪个编译add.c编译的时候会发现,和大家介绍一下。从虚假广告到其他文件对您所提供的功能类型有效,包括以这种方式您自己的头prevents你。

Which the compiler will notice when compiling add.c, and tell you about. Effectively, including your own header in this way prevents you from falsely advertising to other files the type of the functions you are providing.

为什么你可以使用函数而没有宣布它

当你已经注意到了,在某些情况下,你可以实际使用的函数不声明每次它,或者#包括该声明的任何文件。这是愚蠢的,而且每个人都同意,这是愚蠢的。然而,这是C编程语言(和C编译器),如果您使用的功能没有首先声明,它只是假定它是一个简单的返回类型为INT的传统功能。因此,实际上,使用一个功能是隐宣称功能,就好像它是不是已经宣布它返回INT的功能。这是非常奇怪的行为,如果你仔细想想,编译器应该警告你,如果你是这样做的行为。

As you have noticed, in some cases you can actually use a function without every declaring it or #including any file which declares it. This is stupid, and everyone agrees that this is stupid. However, it is a legacy feature of the C programming language (and C compilers) that if you use a function without declaring it first, it just assumes that it is a function returning type "int". So in effect, using a function is implicitly declaring that function as a function which returns "int" if it is not already declared. It's very strange behavior if you think about it, and the compiler should warn you if you it doing that behavior.

头逆天

另外一个常见的​​做法是使用页眉卫士的。为了解释头卫士,让我们来看看可能出现的问题。比方说,我们有两个文件:herp.c和derp.c,他们的两个的要使用包含在每个等功能。按照上述准则,你可能有一个herp.h与行

One other common practice is the use of "Header Guards". To explain header guards, let's look at a possible problem. Let's say that we have two files: herp.c, and derp.c, and they both want to use functions contained in each other. Following the above guidelines, you might have a herp.h with the line

#include "derp.h"

和与该行一个derp.h

and a derp.h with the line

#include "herp.h"

现在,如果你仔细想想,#包括derp.h将被转换为derp.h的内容,又包含该行的#includeherp.h,这将被转换为内容的herp.h和的包含...等等,所以编译器将永远持续下去只是扩大包括。同样,如果main.h#包括两个herp.h和derp.h,都herp.h和derp.h包括add.h,我们看到,在main.h,我们最终的两个 add.h的副本,一个作为#包括herp.h的结果,和一个为包括derp.h.的结果所以,解决的办法? A头文件保护,即一张code这prevents被执行#included两次任何头。为add.h,例如,以正常的方式来做到这一点是:

Now, if you think about it, #include "derp.h" will be converted to the contents of derp.h, which in turn contains the line #include "herp.h", which will be converted to the contents of herp.h, and that contains... and so on, so the compiler will go on forever just expanding the includes. Similarly, if main.h #includes both herp.h and derp.h, and both herp.h and derp.h include add.h, we see that in main.h, we end up with two copies of add.h, one as a result of #including herp.h, and one as a result of including derp.h. So, the solution? A "Header guard", i.e. a piece of code which prevents any header from being #included twice. For add.h, for example, the normal way to do this is:

#ifndef ADD_H
#define ADD_H

int sqrt(int i);
...
#endif

这件code的基本上是告诉preprocessor(德编译器负责处理所有的#XXX语句的一部分),以检查是否ADD_H已定义。如果不是(如果* <青霉> N 的* DEF),那么它首先定义在本文中的ADD_H(,ADD_H不必限定的作为的话,它仅仅是一个布尔它或者是定义的或没有),并且然后定义的标题的内容的其余部分。但是,如果ADD_H已经定义,那么#包括该文件会做的没有的,因为没有了的#ifndef块外。这样的想法是,只有它被包含在任何给定的文件中的第一次将它实际上任何文本添加到该文件。在此之后,#包括它不会将任何额外的文本添加到您的文件。 ADD_H就是你选择跟踪add.h是否已被列入又一个任意符号。对于每一个标题,你用不同的符号来跟踪是否已被列入尚未与否。例如,herp.h可能会使用HERP_H代替ADD_H。使用头文件保护将修复任何我上面列出的问题,其中的文件中包含有重复的副​​本,或者#包括的无限循环。

This piece of code is essentially telling the preprocessor (the part of teh compiler which handles all of the "#XXX" statements) to check if "ADD_H" is already defined. If it isn't (if*n*def) then it first defines "ADD_H" (in this context, ADD_H doesn't have to be defined as anything, it is just a boolean which is either defined or not), and then defines the rest of the contents of the header. However, if ADD_H is already defined, then #including this file will do nothing, because there is nothing outside of the #ifndef block. So the idea is that only the first time it is included in any given file will it actually add any text to that file. After that, #including it will not add any additional text to your file. ADD_H is just an arbitrary symbol you choose to keep track of whether add.h has been included yet. For every header, you use a different symbol to keep track of whether it has been included yet or not. For example, herp.h would probably use HERP_H instead of ADD_H. Using a "header guard" will fix any of the problems I listed above, where you have duplicate copies of a file included, or an infinite loop of #includes.

这篇关于调用另一个文件中的函数在C相同的目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆