代码之家  ›  专栏  ›  技术社区  ›  ufk

用cmake编译cpp项目的重复符号[duplicate]

  •  -2
  • ufk  · 技术社区  · 6 年前

    文件1.c:

    #include <stdio.h>
    #include "global.h"
    
    int main()
    {
        i = 100;
        printf("%d\n",i);
        foo();
        return 0;
    }
    

    文件2.c

    #include <stdio.h>
    #include "global.h"
    
    void foo()
    {
        i = 10;
        printf("%d\n",i);
    }
    

    int i;
    extern void foo()
    

    当我做gcc file1.c file2.c时,一切都很好,我得到了预期的输出。现在,当我初始化头文件中的变量“I”为0并再次编译时,我得到一个链接器错误:

    /tmp/cc0oj7yA.o:(.bss+0x0): multiple definition of `i'
    /tmp/cckd7TTI.o:(.bss+0x0): first defined here
    

    如果我只编译file1.c(删除对foo()的调用)并在头文件中初始化,即gcc file1.c,那么一切正常。怎么回事?

    0 回复  |  直到 11 年前
        1
  •  53
  •   glglgl John Dvorak    13 年前

    有三种情况,请描述:

    1. 带2个 .c int i; 在标题中。
    2. 带2个 文件和 int i=100; 在头中(或任何其他值;这无关紧要)。
    3. 文件和

    在每个场景中,假设头文件的内容插入到 文件和这个 .c .o 文件,然后这些链接在一起。

    然后发生以下情况:

    1. 因为已经提到了“暂定定义”:每 .o 文件包含其中一个,因此链接器显示“ok”。

    2. 不起作用,因为两者都 文件包含一个带有值的定义,该定义会发生冲突(即使它们具有相同的值)–所有文件中可能只有一个具有给定名称 在给定时间链接在一起的文件。

    3. 当然有用,因为你只有一个 .o 所以不可能发生碰撞。

    • extern int i; 或者只是 在头文件中,
    • int i = 100; )进入 file1.c main() 可以省略。(另外,我希望命名只是一个例子;请不要将任何全局变量命名为 i 在实际程序中。)
        2
  •  36
  •   Piotr Praszmo    13 年前

    不要初始化头中的变量。将声明放入头中,并在其中一个 c 文件夹。

    在页眉中:

    extern int i;
    

    int i=1;
    
        3
  •  11
  •   M.M    5 年前

    不应在头文件中定义全局变量。你可以声明为 extern 在头文件中定义它们 .c

    (注:在C中, int i;

        4
  •  2
  •   Nicolas Garnier    7 年前

    定义

    文件1.c:

    #include <stdio.h>
    
    #define DEFINE_I
    #include "global.h"
    
    int main()
    {
        printf("%d\n",i);
        foo();
        return 0;
    }
    

    #include <stdio.h>
    #include "global.h"
    
    void foo()
    {
        i = 54;
        printf("%d\n",i);
    }
    

    全局.h:

    #ifdef DEFINE_I
    int i = 42;
    #else
    extern int i;
    #endif
    
    void foo();
    

    在这种情况下, i 定义 在您定义的编译单元中 宣布 其他地方。链接器不抱怨。

    我以前见过很多次这样的例子,在头中声明了enum,下面是一个char**的定义,其中包含相应的标签。我确实理解为什么作者更喜欢在头文件中包含该定义,而不是将其放入特定的源文件中,但我不确定实现是否如此优雅。

        5
  •  2
  •   M.M    5 年前

    这个 currently-accepted answer

    如果翻译单元包含一个或多个 标识符,并且转换单元不包含该标识符的外部定义,那么该行为就好像转换单元包含该标识符的文件范围声明一样,复合类型位于转换单元的末尾,初始值设定项等于0。

    file1.c file2.c int i = 0; 最后,由于多个外部定义(6.9/5)而导致未定义的行为。

    以下是关于同一代码的两个问题,答案正确:

        6
  •  1
  •   Anand Nekkunti    10 年前

    不要在头文件中定义varibale,在头文件中做声明(良好做法)。。在你的例子中,这是因为多个弱符号。。阅读弱和强符号….链接: http://csapp.cs.cmu.edu/public/ch7-preview.pdf

    这种类型的代码在移植时会产生问题。

    推荐文章