C语言 从C中同一目录中的另一个文件调用函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6618921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling a function from another file in the same directory in C
提问by MohamedEzz
I'm learning C, but i have a long experience with higher level programming languages like Java.
我正在学习 C,但我在 Java 等高级编程语言方面有很长的经验。
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 (it's in the same directory), how is that possible ?! Is it the make file, linker that is configured that way or what ?
我正在阅读头文件,所以我正在玩它们,但是我注意到我可以从另一个文件调用一个函数而无需 #include 它(它在同一目录中),这怎么可能?!是以这种方式配置的make文件,链接器还是什么?
We have two files
我们有两个文件
main.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 more confusing is that when i #include add.c, it gives a multiple-definition error on function add
main.c 调用add(int x,int y)add add.c 中的函数,但我错误地在 #include add.c 之前编译并且它起作用了!更令人困惑的是,当我 #include add.c 时,它在函数 add 上给出了多定义错误
回答by Jeremy Salwen
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.
并且编译器会期望函数“square”在别处定义。
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 botha definition and a declaration. First, you define square in add.c. Then, you declareit 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
现在,如果您有两个不同的文件要互操作(例如,假设函数“square”在 add.c 中定义,而您想在 main.c 中调用 square(10)),则需要这样做既定义和声明。首先,您在 add.c 中定义 square。然后,您在 main.c 的开头声明它。这让编译器在编译 main.c 时知道有一个在别处定义的函数“square”。现在,您需要将 main.c 和 add.c 编译成目标文件。你可以通过调用来做到这一点
gcc -c main.c
gcc -c add.c
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 linkmain.o into a program, i.e.
这将生成文件 main.o 和 add.o。它们包含已编译的函数,但不是完全可执行的。这里要理解的重要一点是 main.o 在某种意义上是“不完整的”。在编译 main.o 时,你告诉它函数“square”存在,但函数“square”在 main.o 中没有定义。因此 main.o 对函数“square”有一种“悬空引用”。它不会编译成一个完整的程序,除非您将它与另一个包含“square”定义的 .o(或 .so 或 .a)文件结合起来。如果您只是尝试将main.o链接到程序中,即
gcc -o executable main.o
You will get an error, because the compiler will try to resolvethe 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 resolvingall these references to undefined functions while converting .o files to executables or .so files), then there won't be any problem. i.e.
您将收到错误消息,因为编译器将尝试解析对函数“square”的悬空引用,但找不到它的任何定义。但是,如果在链接时包含 add.o(链接是在将 .o 文件转换为可执行文件或 .so 文件时解析所有这些对未定义函数的引用的过程),那么就不会有任何问题。IE
gcc -o executable main.o add.o
So that's how to functionallyuse 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 justthe declarations of the functions, withouttheir 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 declarationsof all the functions of add.c.
这就是如何跨 C 文件在功能上使用函数,但在风格上,我刚刚向您展示的是“不是正确的方式”。我这样做的唯一原因是因为我认为它会更好地帮助您了解正在发生的事情,而不是依赖“#include 魔术”。现在,您可能已经注意到,如果您必须在 main.c 的顶部重新声明要使用的每个函数,事情会变得有点混乱。 . 一个头的想法是,它包含只是功能的声明,不他们的定义。这样,为了使用 add.c 中定义的函数编译程序,您无需手动声明您正在使用的每个函数,也无需在代码中 #include 整个 add.c 文件。相反,你可以#包括add.h,其中只包含了声明的add.c.的所有功能
Now, a refresher on #include: #include simply copies the contents of one file directly into another. So, for example, the code
现在,复习一下#include:#include 只是将一个文件的内容直接复制到另一个文件中。所以,例如,代码
abc
#include "wtf.txt"
def
is exactly equivalent to
完全等同于
abc
hello world
def
assuming that wtf.txt contains the text "hello world".
假设 wtf.txt 包含文本“hello world”。
So, if we put all the declarations of add.c in add.h (i.e.
所以,如果我们把 add.c 的所有声明都放在 add.h 中(即
int square(int i);
and then at the top of main.c, we write
然后在main.c的顶部,我们写
#include "add.h"
This is functionally the same as if we had just manually declared the function "square" at the top of main.c.
这在功能上与我们刚刚在 main.c 顶部手动声明函数“square”一样。
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.
所以使用头文件的一般想法是,你可以有一个特殊的文件,通过 #include 自动声明你需要的所有函数。
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:
但是,标头还有一个更常见的用途。假设 main.c 使用来自 50 个不同文件的函数。main.c 的顶部看起来像:
#include "add.h"
#include "divide.h"
#include "multiply.h"
#include "eat-pie.h"
...
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 twopurposes. It declares the functions in main.c for use when included by other files, andit includes all of the dependencies of main.c when included from main.c. Using it this way also allows chainsof 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 theyuse, and so on.
相反,人们经常将所有这些#includes 移动到 main.h 头文件中,而只将 #include main.h 移动到 main.c 中。在这种情况下,头文件有两个目的。它声明 main.c 中的函数在被其他文件包含时使用,当从 main.c 包含时,它包含 main.c 的所有依赖项。以这种方式使用它也允许依赖链。如果您#include add.h,您不仅可以获得在add.c 中定义的函数,而且还可以隐式获得add.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
此外,更巧妙的是,#include 来自它自己的 .c 文件的头文件会隐式地检查您所犯的错误。例如,如果您不小心将正方形定义为
double square(int i);
in add.h, you normally might not realize until you were linking that main.o is looking for onedefinition of square, and add.o is providing another, incompatibleone. 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
在 add.h 中,您通常在链接之前可能不会意识到 main.o 正在寻找一个正方形的定义,而 add.o 正在提供另一个不兼容的定义。这将导致您在链接时出现错误,因此您直到构建过程的后期才会意识到错误。但是,如果你从 add.c #include add.h 到编译器,你的文件看起来像
#include "add.h"
int square(int i) {
return i*i;
}
which after processing the #include statement will look like
在处理 #include 语句后,它看起来像
double square(int i);
int square(int i) {
return i*i;
}
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.
编译器在编译 add.c 时会注意到哪些,并告诉你。实际上,以这种方式包含您自己的标题可以防止您向其他文件错误地宣传您提供的功能类型。
Why you can use a function without ever declaring it
为什么不用声明就可以使用函数
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.
正如您所注意到的,在某些情况下,您实际上可以使用一个函数,而无需每个人都声明它或 #include 任何声明它的文件。这是愚蠢的,每个人都同意这是愚蠢的。然而,这是 C 编程语言(和 C 编译器)的一个遗留特性,如果你使用一个函数而不先声明它,它只是假设它是一个返回类型“int”的函数。因此,实际上,使用函数就是隐式地将该函数声明为一个函数,如果该函数尚未声明,则该函数返回“int”。如果您考虑一下,这是非常奇怪的行为,如果您这样做,编译器应该警告您。
Header Guards
头卫队
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 bothwant to use functions contained in each other. Following the above guidelines, you might have a herp.h with the line
另一种常见做法是使用“Header Guards”。为了解释标题守卫,让我们看看一个可能的问题。比方说,我们有两个文件:herp.c和derp.c,他们既要使用的功能包含在彼此。遵循上述指导方针,您可能有一个带有行的 herp.h
#include "derp.h"
and a derp.h with the line
以及带有该行的 derp.h
#include "herp.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 thatcontains... 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 twocopies 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:
现在,如果您考虑一下,#include "derp.h" 将被转换为derp.h 的内容,后者又包含行#include "herp.h",该行将被转换为herp 的内容。小时,即包含...等等,所以编译器将永远持续下去只是扩大包括。类似地,如果main.h #includes herp.h和derp.h,并且herp.h和derp.h都包括add.h,我们看到在main.h中,我们最终得到了add.h的两个副本,一种是因为#include herp.h,一种是因为包括derp.h。那么,解决方案?“标题保护”,即防止任何标题被#include 两次的一段代码。例如,对于 add.h,执行此操作的正常方法是:
#ifndef ADD_H
#define ADD_H
int sqrt(int i);
...
#endif
This piece of code is essentially telling the preprocessor (the part of the compiler which handles all of the "#XXX" statements) to check if "ADD_H" is already defined. If it isn't (ifndef) then it first defines "ADD_H" (in this context, ADD_H doesn't have to be defined asanything, 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.
这段代码本质上是告诉预处理器(编译器中处理所有“#XXX”语句的部分)检查是否已经定义了“ADD_H”。如果不是(如果ndef),那么它首先定义“ADD_H”(在这种情况下,ADD_H 不必定义为任何东西,它只是一个定义或未定义的布尔值),然后定义标题的其余内容。但是,如果已经定义了 ADD_H,那么 #include 这个文件将什么也不做,因为 #ifndef 块之外没有任何内容。所以这个想法是,只有第一次将它包含在任何给定文件中时,它才会实际向该文件添加任何文本。之后,#include 不会向您的文件添加任何其他文本。ADD_H 只是您选择用来跟踪是否已包含 add.h 的任意符号。对于每个标题,您使用不同的符号来跟踪它是否已包含在内。例如,herp.h 可能会使用 HERP_H 而不是 ADD_H。使用“标题保护”将解决我上面列出的任何问题,其中包含文件的重复副本或#includes 的无限循环。
回答by Chris Lutz
The problem is that you shouldn't be #includeing a .c file.
问题是你不应该#include.c 文件。
To use a function in another file, you need to declare it. Usually, every .c file (except main.c) has an associated header (.h) file that properly declares all the functions defined in the .c file. You can declareas many times as you want (so long as all the declarations are identical), but there can only be one definition.
要在另一个文件中使用函数,您需要声明它。通常,每个 .c 文件(main.c 除外)都有一个关联的头文件 (.h),该文件正确声明了 .c 文件中定义的所有函数。您可以根据需要多次声明(只要所有声明都相同),但只能有一个定义。
What happens when you #include "add.c"is that the text of add.c is included in main.c, giving main.c a definition(and, as a side-effect, a declaration) of add. Then, when you compile add.c on it's own, that creates anotherdefinition of add. Thus, there are two definitons of the function, and the compiler freaks out because it doesn't know which one to use.
当#include "add.c"add.c 的文本包含在 main.c 中时会发生什么,给出 main.ca 的定义(并且作为副作用,声明)add. 然后,当你编译add.c它自己,它创建另一个的定义add。因此,该函数有两个定义,编译器吓坏了,因为它不知道该使用哪一个。
If you change it to #include "add.h", where add.h looks something like this:
如果将其更改为#include "add.h",则 add.h 看起来像这样:
#ifndef ADD_H
#define ADD_H
extern int add(int x, int y);
#endif /* ADD_H - Google "include guard" for more info about this trickery */
then main.c has a declaration of addand can use the function, but the definitionof addis quite firmly only in the add.c file, and so it only exists once, and so it will compile properly.
那么main.c中有一个声明add,可以使用的功能,但定义的add相当坚决只在add.c文件,所以只存在一次,所以它会正确编译。
回答by Shameerariff
Here is a simple example of calling a function from different c program
这是从不同的c程序调用函数的简单示例
let me name the main program as main.c and the program that holds the function as function.c for the function.c I am creating the header file called function.h
让我将主程序命名为 main.c,将保存函数的程序命名为 function.c for the function.c 我正在创建名为 function.h 的头文件
main.c
主文件
#include"function.h"
int main()
{
int a = sum(1,2);
return a;
}
function.c
函数.c
int function(int a,int b)
{
return a+b;
}
function.h
函数.h
int function(int,int);
To compile use the command given below
编译使用下面给出的命令
g++ main.c function.c -o main
g++ main.c function.c -o main
Here the detailed explanation. In the main program I have called the function to sum 2 numbers. The values 1 and 2 in the main program was feed to the function in the function.c through the header function.h which holds the access point or the bridge to the function.c
这里有详细的解释。在主程序中,我调用了对 2 个数字求和的函数。主程序中的值 1 和 2 通过头文件 function.h 提供给 function.c 中的函数,该头文件包含访问点或通往 function.c 的网桥
For more details you can check the links given below
有关更多详细信息,您可以查看下面给出的链接
http://www.cplusplus.com/forum/beginner/34691/
http://www.cplusplus.com/forum/beginner/34691/
https://social.msdn.microsoft.com/Forums/en-US/4ea70f43-a0d5-43f8-8e24-78e90f208110/calling-a-function-in-a-file-from-another-file?forum=winembplatdev
https://social.msdn.microsoft.com/Forums/en-US/4ea70f43-a0d5-43f8-8e24-78e90f208110/calling-a-function-in-a-file-from-another-file?forum=winembplatdev
Add a print statement to check the result or use echo $? after execution of the file main
添加打印语句来检查结果或使用 echo $? 执行文件 main 后
回答by Matt Joiner
You're able to call it because a declaration isn't necessary to make a call in C. The return type however is unknown, and so will default to int. This is possible in part due to the default calling convention in C, and the default promotion of types to at least intprecision.
您可以调用它,因为在 C 中进行调用不需要声明。但是返回类型是未知的,因此将默认为int. 这部分是由于 C 中的默认调用约定,以及类型的默认提升至少为int精度。
If you include a header that defines the function you are calling, the compiler is able to check that calls to the function have the correct number and type of arguments.
如果包含定义正在调用的函数的头文件,编译器能够检查对函数的调用是否具有正确的参数数量和类型。
If you include function definitions, they will be exported unless you specify their storage with static. Since you're also compiling and linking add.c, you can't add this since then either neither or both of your object files will then be exporting add.
如果您包含函数定义,除非您使用static. 由于您也在编译和链接add.c,因此您无法添加它,因为这样您的两个目标文件都不会或两者都将导出add.
If you want to simply include all your functions, best to put their definitions into headers, and sprinkle storage specifiers on them.
如果您想简单地包含所有函数,最好将它们的定义放入标题中,并在其上撒上存储说明符。

