多个定义和第一个定义的错误

Posted

技术标签:

【中文标题】多个定义和第一个定义的错误【英文标题】:Multiple definitions and First defined error 【发布时间】:2016-05-23 18:03:12 【问题描述】:

我编写了一个由几个文件组合而成的小型 C 程序。 编译时出现“多个定义”的错误。

我的 main.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

#define FOREVER for(;;)
#define INPUT_LEN 30

int main()

    char command[INPUT_LEN];
    char *func;
    int i;
    int t;

    FOREVER
    
        if(scanf("%s", command) == 1)
        
            func = strtok(command, " ");
            for(i=0;cmd[i].func != NULL;i++)
            
                if(strcmp(func, cmd[i].name) == 0)
                
                    (*((cmd[i].func)));
                    t = 1;
                
            
            if(t == 1)
            
                printf("No such command");
            
        
       
    return 0;   

我的 mat.c 文件:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

#define LENGTH 100
#define SIXTEEN 16
#define SIZE 4


void read_mat()

    int i = 0;
    int j = 0;
    int k = 0;
    char tmp_name[LENGTH];
    char num_buffer[LENGTH];
    char *token;
    double num_list[16];
    double tmp_num = 0;

    scanf("%[^,], %s", tmp_name, num_buffer);

    token = strtok(num_buffer, ",");

    while(token != NULL)
    
        if(strcmp(token, "0") == 0)
        
            num_list[i] = 0;
        
        else
        
            tmp_num = atof(token);
            if(tmp_num == 0)        
            
                printf("Error in parameter: %d\n", (i-1));
                break;
            
            else
            
                num_list[i] = tmp_num;
            
           
    i++;
    token = strtok(NULL, ",");
    

    if(!strcmp(tmp_name, "MAT_A"))
    
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            
                mats[0].mat[0][i][j] = num_list[k];
                k++;
            

    
    else if(!strcmp(tmp_name, "MAT_B"))
    
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            
                mats[1].mat[0][i][j] = num_list[k];
                k++;
            
    
    else if(!strcmp(tmp_name, "MAT_C"))
    
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            
                mats[2].mat[0][i][j] = num_list[k];
                k++;
            
    
    else if(!strcmp(tmp_name, "MAT_D"))
    
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            
                mats[3].mat[0][i][j] = num_list[k];
                k++;
            
    
    else if(!strcmp(tmp_name, "MAT_E"))
    
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            
                mats[4].mat[0][i][j] = num_list[k];
                k++;
            
    
    else if(!strcmp(tmp_name, "MAT_F"))
    
        for(i=0;i<SIZE;i++)
             for(j=0;j<SIZE;j++)
             
                mats[5].mat[0][i][j] = num_list[k];
                k++;
             
    
    else
    
        printf("No such matrix name.");
    

我的 general_structs.h 文件:

#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10

typedef double matrix[SIZE][SIZE];

matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

void read_mat(void);

struct 

    char name[SIZE_NAME];
    matrix *mat;
 mats[] = 
        "MAT_A", &MAT_A,
        "MAT_B", &MAT_B,
        "MAT_C", &MAT_C,
        "MAT_D", &MAT_D,
        "MAT_E", &MAT_E,
        "MAT_F", &MAT_F,
        "non", NULL
      ;

struct

    char name[SIZE_FUNC];
    void (*func)(void);
 cmd[] = 
        "read_mat", read_mat,
        "not_valid", NULL
      ;

我的制作文件:

int_loop: my_math.o int_loop.o
    gcc -g -ansi -Wall -pedantic my_math.o int_loop.o -o int_loop

int_loop.o : int_loop.c
    gcc -c -ansi -Wall -pedantic int_loop.c -o int_loop.o

my_math.o : my_math.c
    gcc -c -ansi -Wall -pedantic my_math.c -o my_math.o

我一直在尝试用各种技术解决这个问题,但没有成功。

我收到的错误是:

gcc -g -Wall -ansi -pedantic main.o mat.o -o mamantest
mat.o:(.data+0x0): multiple definition of `mats'
main.o:(.data+0x0): first defined here
mat.o:(.data+0x70): multiple definition of `cmd'
main.o:(.data+0x70): first defined here
collect2: ld returned 1 exit status
make: *** [mamantest] Error 1

为什么会出现这个错误?我该如何解决?

谢谢

【问题讨论】:

【参考方案1】:

在头文件中定义变量matscmd,这意味着translation units(包括头文件的两个源文件)都将定义这些变量。

变量应该只定义在一个地方,一个源文件中,比如

struct mat mats[7] =  ... ;

上面定义数组mats,就像我说的应该只在一个地方完成。

对于其他源文件,您声明变量,这可以在头文件中完成,例如

extern struct mat

    ...
 mats[7];

上述声明变量mats 为一个由七个mat 结构组成的数组。它还定义了 结构,因此它可以用于例如定义数组。


经过上述修改后,完整的头文件应该类似于

// First header include guards (see https://en.wikipedia.org/wiki/Include_guard)
#ifndef GENERIC_STRUCTS_H
#define GENERIC_STRUCTS_H

#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10

typedef double matrix[SIZE][SIZE];

// Declare the variables (note the added use of the extern keyword)
extern matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

void read_mat(void);

// Define a structure named mat (note added structure tag name)
struct mat

    char name[SIZE_NAME];
    matrix *mat;
;

// Define a structure named command (note added structure tag name)
struct command

    char name[SIZE_FUNC];
    void (*func)(void);
;

// Now declare variables of the previous structures
extern struct mat mats[7];
extern struct command cmd[2];

// End of header include guard
#endif

该头文件只声明变量,并且可以包含在所有源文件中。

然后在 single 源文件(例如您的 main.c 文件)中执行实际的变量定义:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

struct mat mats[7] = 
    "MAT_A", &MAT_A,
    "MAT_B", &MAT_B,
    "MAT_C", &MAT_C,
    "MAT_D", &MAT_D,
    "MAT_E", &MAT_E,
    "MAT_F", &MAT_F,
    "non", NULL
;

struct command cmd[2] = 
    "read_mat", read_mat,
    "not_valid", NULL
;

#define FOREVER for(;;)
#define INPUT_LEN 30

int main()

    ...

您需要在这里了解的重要一点是,声明定义某事是有区别的。

声明基本上是在告诉编译器“这东西存在于某处”,而定义则是告诉编译器“这就是这个东西”。

问题在于,除非一个事物已经被声明,否则定义也是一个声明,许多人简单地将这些组合的定义/声明称为声明,这使整个概念有点混乱。

【讨论】:

如果我这样做,我将没有“$.h”文件 (general_structs.h)。因为拥有一个是任务的一部分.. @JinKazama 您仍然需要 结构 定义的头文件、matrix 类型别名和变量的声明。您只需将这些变量的定义 移动到单个源文件中。用修改后的头文件更新了我的答案。 嘿,感谢您提供的非常有用的回答。如果结构的“定义”部分应该只在一个源文件中(例如,“main.c”),那么另一个文件(“mat.c”)将不知道这些结构。这就是为什么我认为它们应该在标题中,所有来源都可以接近和阅读。对不对? @JinKazama 定义结构和定义变量是两件不同的事情。结构定义是编译器专用的,一旦编译器有了结构定义,它就不再需要了,也不会保存到目标文件中。另一方面,变量定义 存储在目标文件中。这就是为什么在头文件中定义变量会导致多个定义错误的原因,因为它将在两个或多个目标文件中定义。所以就像在我的例子中,实际结构的定义可以在头文件中,但不能在变量的定义中。 再次感谢您快速而翔实的回答。所以如果我在 1 个源文件“main.c”中定义变量,如果我调用它们,另一个源文件“mat.c”会知道这些变量吗?

以上是关于多个定义和第一个定义的错误的主要内容,如果未能解决你的问题,请参考以下文章

自定义丢失函数,具有多个输出并使用add_loss

控制系统设计指南第1章和第2章读书笔记

带有自定义查询集的表单向导

Michael Hartl的Rails教程第11章和第12章:多个错误和邮件未被发送

VC MFC下 定义 CString str 怎样获取str的第二个和第三字符(用啥函数)?

带有 TextField 和第一响应者的自定义 UITableViewCell