多个定义和第一个定义的错误
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】:在头文件中定义变量mats
和cmd
,这意味着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”会知道这些变量吗?以上是关于多个定义和第一个定义的错误的主要内容,如果未能解决你的问题,请参考以下文章
Michael Hartl的Rails教程第11章和第12章:多个错误和邮件未被发送