如何编译具有多个主函数的C项目?

时间:2010-05-21 05:25:25

标签: c ide linker qt-creator

我是C的新手,现在阅读一些教科书并开始应用它的例子。

问题是,每当我创建一个新项目并尝试放置包含main函数的多个文件时,链接器(正如我thougt0解释说的那样:

/home/mohammed/tmp/abcd/main.c:4: multiple definition of `main'

(BTW,我使用过很多IDE,MonoDevelop,QT创建者,VS2010,Codebloks,...) 我目前使用QT Creator,它似乎是一个非常好的IDE。

那么,解决这样的问题没有解决办法吗?

编辑:

我在问,因为我处于学习阶段,现在没有真正的编程。 我只需要一种简单的方法来在C中创建程序,而不必为每个书籍示例创建一个单独的项目。 同时,我不想使用Gedit / VI +命令行。

那么,是不是有任何方法,比如清理项目,然后编译 - 只需一个文件,我需要运行??? 顺便说一句,在JAVA中,我们可以运行一个程序,它包含多个主程序(IDE给我选择)

15 个答案:

答案 0 :(得分:10)

你想用多个main函数做什么?

如果您尝试一次编译多个不同的程序,则需要单独编译每个程序(即每个程序只编译一个main)。

如果您正在尝试编译一个程序并希望运行多个main函数 all ,则不能。您只需要指定一个main并将其他人重命名为其他内容(并按照您希望它们运行的​​顺序从单个main中调用它们。)

如果您尝试仅使用其中一个main函数作为程序的单个入口点而忽略其他函数,那么当您使用其他main时,不应包含这些文件正在联系。如果您希望保留它们,我建议将每个main放在一个单独的文件中,并在链接/编译时只包含其中一个主文件。

如果您错误地收到此错误,那么您可能在IDE中执行了错误的项目。也许你不小心尝试将多个不同的程序编译成一个?您可能需要将包含main的每个文件指定为单独的构建产品。 C与Java不同,您可以在每个类中放置main方法并指定要调用的方法; C中的main是全局名称。

答案 1 :(得分:5)

您的应用程序中不可能有多个入口点。 启动最终可执行文件时,将调用入口点函数(main)。而且这个不能含糊不清。

因此,如果您想逐个调用它们,您可以将它们链接起来:

void main1() {} /* Note that these aren't called main. */
void main2() {}
...

int main(int argc, char* argv[]) {
    main1();
    main2();
    return 0;
}

您甚至可以使用线程(例如boost.Thread)调用它们,以便它们并行运行。 但是,您不能将多个名为main的函数链接在一起。

如果您希望它们分别是单独的程序,则必须单独链接它们。

答案 2 :(得分:2)

每个程序必须只有一个主要功能。但是,main可以调用你想要的任何函数(包括它自己,虽然这可能会令人困惑)。因此,您应该将程序分解为逻辑部分。

答案 3 :(得分:2)

正如许多人所说,每个节目只能有一个主要节目。在阅读本书时,您不希望为每个示例创建一个新项目的麻烦。这是可以理解的,但基本上你必须这样做。我看到两种选择:

  1. 在IDE中使用新项目功能(如VS2010)。这将为您完成所有艰苦的工作。您可以随时删除它们。
  2. 如果您不想保留代码,只需清空文件(甚至是main()函数)并重新使用它。使用书籍示例,您可能永远不会重新访问代码,因此只需删除它就可以了。

答案 4 :(得分:2)

如果每个main都对应于构建目录树中的不同可执行文件,那么在同一个项目中可以有多个main。

以下示例使用CMake,我不知道是否可以使用其他构建过程管理器软件。

将以下两个.cpp文件存储在名为 source 的文件夹中,并将其命名为square_root.cpp和power_of_two.cpp:

square_root.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main (int argc, char *argv[])
{

  if (argc < 2) {
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
  }

  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);

  return 0;
}

power_of_two.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main (int argc, char *argv[])

{
  if (argc < 2) {
      fprintf(stdout,"Usage: %s number\n",argv[0]);
      return 1;
  }

  double inputValue = atof(argv[1]);
  double outputValue = inputValue*inputValue;

  fprintf(stdout,"The power of two of %g is %g\n",
          inputValue, outputValue);

  return 0;
}

请注意,它们都包含方法main。 然后,在同一个文件夹中,添加一个名为CmakeLists.txt的.txt:它会告诉编译器可执行文件的数量,如何调用它们以及在哪里找到main .s。

的CMakeLists.txt:

cmake_minimum_required (VERSION 2.6)
project (Square_and_Power)
add_executable(Square2 square_root.cpp)
add_executable(Power2 power_of_two.cpp)

在源的同一根中创建一个名为build的新文件夹,然后使用cmake进行配置和生成。看一下在文件夹构建中创建的文件夹的结构。 在构建中打开终端并键入 make

 →  make
[ 50%] Built target Power2
Scanning dependencies of target Square2
[ 75%] Building CXX object CMakeFiles/Square2.dir/square_root.cpp.o
[100%] Linking CXX executable Square2
[100%] Built target Square2

如果没有错误发生,您将有两个可执行文件:Square2和Power2。

→  ./Square2 5
The square root of 5 is 2.23607
 →  ./Power2 5
The power of two of 5 is 25

所以你有两个主要编译两个不同应用程序的项目。然后,两个cpp文件可以在项目中的其他.cpp或.h文件中共享相同的标头和其他方法。 我建议你看看cmake教程https://cmake.org/cmake-tutorial/ 可能有其他方法有相似但不相同的结果,但我不知道。希望其他用户将为此主题做出贡献!

答案 5 :(得分:1)

实际上,我发现Dev-C ++支持处理不属于任何项目的多个主文件,因此我可以创建一个运行尽可能多的文件。

感谢所有合作伙伴:) 为所有人带来好运。

另外,对于Linux / win,我发现Code :: Blocks可以做到这一点。感谢。

答案 6 :(得分:0)

我猜你的一个IDE会自动创建一个main函数的文件。检查周围是否已经创建了一个。

答案 7 :(得分:0)

您不能拥有main的多个定义。 “主要”功能实质上是定义程序的功能。如果您有多个main副本,您希望执行哪个副本?

您的问题的解决方案是使用库;如果你想重用功能,那么你应该创建一个库,它与程序基本相同,只是它有功能和数据(如程序),它没有一个叫做“main”的特殊功能,因此没有“入口点”,执行应该在操作系统双击或以其他方式加载时开始。库有两种变体:共享/动态和静态。任何人都应该这样做。您创建的每个程序都有自己的主要功能,但您可以在不同的程序中重复使用您的库。

现在关于创建图书馆的实际要素......请参阅我的C++ Library Project Template

答案 8 :(得分:0)

正如其他人所说,你的项目可能只有一个主要功能。

为什么要尝试多个主要功能?是因为您将多个小示例程序放入一个项目中,并且每个项目都有一个主要的?如果是这种情况,您可能需要为每个示例创建一个单独的项目,以便IDE不会要求编译器将来自多个示例的源代码编译/链接到一个程序中。您的IDE也可能支持像目标这样的概念,它允许您在一个项目中保留多个相关程序的代码,而不是选择实际构建的程序(目标)。然后,IDE将仅编译/链接该目标中的文件。

答案 9 :(得分:0)

尝试使用静态关键字,例如:

file1.cpp:

#ifdef RUN_FILE1
#define STATIC static
#else
#define STATIC
#endif

int STATIC main(int argc, char **argv(){}

file2.cpp:

#ifdef RUN_FILE2
#define STATIC static
#else
#define STATIC
#endif

int STATIC main(int argc, char **argv(){}

用于汇编添加/DRUN_FILE2/DRUN_FILE1

只是一个想法。

答案 10 :(得分:0)

如果您正在使用MS链接器,请使用/ FORCE:MULTIPLE链接器选项。遇到的第一个主要符号将获胜。不确定其他连接器的选项是什么。

答案 11 :(得分:0)

我认为QtCreator是一个很棒的IDE。

对于学习和测试,能够拥有多个是很好的 主电源易于使用,但如前所述,您只能有一个主电源 因为这就是在QTcreator / .pro qmake文件中定义项目的方式。

您可以在pro或make / CMAKE文件中创建多个目标。

但是对于测试,我在项目的.pro文件中做了这个。


MAIN = simpletree_test.c

SOURCES += \
    $$MAIN \
    simpletree.c \
    graph_tree.c \
    redblacktreenode.c \
    redblacktree.c \
    redblack.c \
    pointers.c

HEADERS += \
    simpletree.h \
    graph_tree.h \
    redblacktreenode.h \
    redblacktree.h \
    redblack.h \
    pointer_manipulator.h

message("The project contains the following files:")
message($$SOURCES)

所以我只是在专业文件中交换名为MAIN的变量中的主文件名。 在SOURCES变量中使用它。

正如您所看到的,我测试了几种树的实现。 现在正在测试树的简单变体,在测试特定节点的新实现之前,在平衡树上测试它们。

然而,该方法并不完美,因为您不能为函数等命名。 过了一段时间,我很难为find_node()或traverse_tree()

提出新名称

答案 12 :(得分:0)

在QtCreator中,您可以右键单击文件并选择“编译”选项,该选项仅编译所选文件和所需的依赖项。因此,如果您编译一个这样的主文件,并且该文件不包含任何其他主文件,那么这应该可行。

答案 13 :(得分:0)

我能找到的最佳解决方案是Eclipse creating projects every time to run a single file?,除了为每个程序创建一个新项目之外,还有其他选择。

答案 14 :(得分:0)

NOT:我在这里解释了 cpp 但如果你想为 c 语言做只需要改变编译器 g++ gcc

这是一个老问题,但我想我理解你提出的问题。

是的,正如您所说,在一个项目中,我们需要使用多个文件,例如ma​​in.cpptest1.cpp 等,但是,我们应该在项目中只有一个“ma​​in()”函数。

但是,当你想对任何 cpp 文件进行独立测试时,编译器会提示“这个文件中我宝贵的 main() 或 _start() 函数在哪里?”,终端输出喜欢:

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status

解决方案是使用#ifdef / #endif机制。如下图:

示例项目结构:

enter image description here

main.cpp 函数:

#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "MAIN" << std::endl;
    return 0;
}

我们的测试脚本,cpp代码(vector_test.cpp):

#include <iostream>

using namespace std;

int vmain()
{
    std::cout << "vmain -> ifdef" << std::endl;
    return 0;
}

#ifdef TESTING
int main(int argc, char *argv[])
{
    vmain();
    return 0;
}
#endif

因此,当您运行项目时,永远不会出现任何编译时错误,因为您使用 #ifdef 在其他脚本中隐藏了其他主要函数。

当您需要测试任何脚本时,只需在编译时添加如下参数即可:

$ g++ -DTESTING vector_test.cpp
$ ./a.out

输出为:

<块引用>

vmain -> ifdef

如您所见,这种方法类似于著名的python

def main():
    #do somethings

if __name__ == "__main__":
   main()

方法。