【问题标题】:calling functions from a different c file从不同的 c 文件调用函数
【发布时间】:2014-09-02 07:17:01
【问题描述】:

实际上我正在编译多个文件。以下是文件:

文件 main.c -->

#include <stdio.h>
void foo3(void)
{
        printf("INSIDE foo3 function\n");
}

int main()
{
        foo1();
        foo2();
        foo3();
}

文件 1.c -->

#include <stdio.h>
void foo1(void)
{
        printf("INSIDE foo1 function\n");
}

文件 2.c-->

#include <stdio.h>
void foo2(void)
{
        printf("INSIDE foo2 function\n");
}

现在我使用 gcc 编译如下-->

gcc 1.c 2.c main.c -o main

以下是输出-->

INSIDE foo1 function
INSIDE foo2 function
INSIDE foo3 function

我的疑问是main() 在main.c 中未声明时如何调用foo1()foo2()。但是现在如果我将 main.c 更改如下(在main() 之后编写foo3() 的定义),如下所示:

编辑 main.c -->

#include <stdio.h>
int main()
{
        foo1();
        foo2();
        foo3();
}

void foo3(void)
{
        printf("INSIDE foo3 function\n");
}

然后如果我编译我得到这个错误:

main.c:9:6: warning: conflicting types for ‘foo3’ [enabled by default]
 void foo3(void)
      ^
main.c:6:2: note: previous implicit declaration of ‘foo3’ was here
  foo3();
  ^

为什么在 foo1()foo2() 的情况下之前没有显示此错误。先感谢您。

【问题讨论】:

    标签: gcc compilation linker function-declaration definitions


    【解决方案1】:

    我的疑问是,main()foo1()foo2() 未在 main.c 中声明时如何调用它们

    因为GCC 编译器默认使用旧的ANSI C(也称为C89)语言,其中允许未声明的函数并默认给出int 结果。

    尝试调用编译器,例如

     gcc -std=c99 -Wall -g -c main.c
    

    或者(如果你想一次编译所有文件)

     gcc -std=c99 -Wall -g 1.c 2.c main.c -o main
    

    您可以使用 recent GCC 来请求 link time interprocedural optimizationsgcc -flto 而不是 gcc,例如GCC 4.9 2014 年 9 月。

    这需要一个符合C99 的源代码,所有函数都应在其中声明。 -Wall 要求(几乎)所有警告。 -g 选项产生一个可调试的目标代码(或用于同时编译所有文件的最后一个命令的可执行文件)。

    在您编辑的main.c 中,当foo3 第一次出现(在main 内)时,编译器猜测它是一个返回int 的函数。当编译器看到foo3 的定义时,它会正确地抱怨。

    您可以使用-Wstrict-prototypes 警告optiongcc(但我始终建议使用-Wall 暗示)。

    在链接时,C 函数的类型(和签名)并不重要。链接器只使用名称来完成它的工作(但 C++ 使用 name mangling)。当然,使用不正确的参数或结果调用函数是undefined behavior

    良好的常规做法是在源文件中使用一个通用的头文件来声明所有使用的和公共的函数和类型(以及常量)和include 该头文件(这样可以避免多次复制和粘贴这些声明)。所以你应该有一个新的头文件myheader.h 喜欢

    // file myheader.h
    #ifndef MY_HEADER_INCLUDED
    #define MY_HEADER_INCLUDED
    void foo1(void);
    void foo2(void);
    void foo3(void);
    #endif /*MY_HEADER_INCLUDED*/
    

    并且您将在所有源文件中添加#include "myheader.h"(在#include &lt;stdio.h&gt; 指令之后)。注意include guardMY_HEADER_INCLUDED 的技巧。

    实际上,头文件通常包含解释程序的API 的cmets。

    还可以了解GNU make。它将简化您的多源代码文件程序的构建(您只需通过运行make 进行编译和构建)。请参阅thisthatMakefile 示例。明白C preprocessing是C编译的第一阶段。

    【讨论】:

    • 感谢您提供宝贵的信息。还有一个疑问。为什么它没有显示 foo2() 和 foo1() 的冲突类型警告,当它们也像 foo3() 一样第一次出现在 main() 中,而 main.c 中没有任何先前的声明。
    • 您需要为此进行链接时间优化。但是对你来说重要的是养成编写和使用头文件的习惯,并在那里声明所有公共的东西。
    • 哦,好吧。 main.c 编译只会显示 foo3.c 的警告,因为它只是在 main.c 中定义的函数。因此,上面对 foo3() 的警告是 main.c 中的唯一警告,其他函数在 main.c 编译期间假定返回 int 类型,因此不会对它们发出警告,因为它们的定义在 main 编译时不会发生。C。感谢您的宝贵支持。
    猜你喜欢
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    相关资源
    最近更新 更多