"已定义" VC ++中的错误

时间:2014-05-27 15:09:46

标签: c data-structures

我正在学习以专业的方式编写程序。就像,通过创建单独的.C和.h文件。我决定用结构编写一个简单的代码,但我收到错误。 我做过这些事情:

/*---list.h file-------*/
#ifndef LIST_H
#define LIST_H
struct list{
    int a;
    struct list *next;
};
typedef struct list LIST;
LIST *pHead=NULL,*pCurrent=NULL;
void display(void);

#endif


/*---list.c file ---*/
#include "main.h"


    void display()
    {
        pHead->a=100;
        printf("%d",pHead->a);
    }


/*----main.h file-----*/

#ifndef MAIN_H
#define MAIN_H

#include<stdio.h>

#include "list.h"
#endif


/*---main.c file---*/
#include "main.h"


void main(void)
{
LIST *New=pHead;
display();
printf("\n\n%d",New->a);
getch();

}

当我编译代码时,我遇到了以下错误 1&gt; main.obj:错误LNK2005:_pCurrent已在list.obj中定义 1&gt; main.obj:错误LNK2005:_pHead已在list.obj中定义

谁能告诉我我做错了什么?我是否包括两次,因为我得到了重新声明错误?

3 个答案:

答案 0 :(得分:2)

这是因为您定义了标题中的内容,而不是仅仅声明

此:

LIST *pHead=NULL,*pCurrent=NULL;

表示包含列表标题的每个C文件都尝试创建两个全局变量。然后,当您将这些C文件链接在一起时,这些变量会发生冲突。这打破了,你永远不应该这样做。永远不要在标题中定义内容。

答案 1 :(得分:2)

您在头文件中定义了对象,然后将它们包含在多个源文件中,从而打破了one definition rule

如果您想创建可在不同翻译单元中使用的全局变量,则应use the extern keyword

答案 2 :(得分:1)

一般来说,.c个文件包含变量,函数等的实例。虽然.h文件包含变量,函数等的原型,但在它的伴随.c文件中找到。

通常情况下,变量和函数体不会放在.h文件中; 只有变量和函数原型应放在.h文件中。

在考虑如何将代码分割成单独的文件时,重要的是要考虑哪些函数,结构和宏是最原始的。例如,如果你写两个函数,并且函数&#39; a&#39;呼叫功能&#39; b&#39;,功能&#39; b&#39;是最原始的

这个想法是将功能分组为一个&#39; c&#39;相关的文件,并且处于类似的原始级别。

在这个问题的情况下,更原始的列表函数应该体现在list.c中。然后&#39; list.h&#39;用于原型化其他不太原始的 .c文件(如main.c)使用的函数和结构。

大多数原始函数也是最自给自足的。虽然不太原始的函数应该调用更原始的函数,但反过来却会导致笨拙的代码流。

现在查看问题代码:

/*---list.c file ---*/
#include "main.h"

list.c应被视为更原始而不是main.c。因此,list.c包含main.h(专业)并不是一个好主意。 list.c更原始应该更自给自足。

main.h不是包含list.c,而是将list.h包含在自己的void display() { pHead->a=100; printf("%d",pHead->a); } 中,以便它可以访问自己的`struct list& #39;定义等。

list.c

为了更好地隔离/*---list.h file-------*/ #ifndef LIST_H #define LIST_H typedef struct NODE_S { int a; struct list *next; } NODE_T; typedef struct LIST_S { NODE_T *head; } LIST_T; extern void NodeDisplay(NODE_T *node); #endif /*---list.c file ---*/ #include <stdio.h> // printf() #include "list.h" // NODE_T, LIST_T void NodeDisplay(NODE_T *node) { printf("%d\n",pHead->a); return; } ,上述功能不应引用全局&#39;变量(pHead)。相反,最好让节点显示&#39;作为参数传递给函数。

考虑到这一点,以下是&#39; list.c&#39;和&#39; list.h&#39;可能会有所改进:

pHead

请注意pCurrentlist.h并非list.clist.c中的原型或体现,list.h中没有使用这些变量,而且没有功能性的理由将它们放在main.h


现在检查问题代码中的main.c/*----main.h file-----*/ #ifndef MAIN_H #define MAIN_H #include<stdio.h> #include "list.h" #endif

stdio.h

单独地,main.h需要list.hmain.h的目的是什么?如果将它们删除,是否会留下一些未定义的内容。在&#39; main.h&#39;?也许这两个包含文件并不属于main.h。 &#34;但如果将它们从main.h中删除,为什么还要有一个main.h?&#34;好点子。也许main.c没有任何目的,甚至可能不存在。

/*---main.c file---*/ #include "main.h" void main(void) { LIST *New=pHead; display(); printf("\n\n%d",New->a); getch(); } 文件是所有文件的最原始,并且通常不应该将任何内容导出到其他(更原始的)文件。< / p>

main.c

那么printf()究竟需要什么?它需要调用stdio.h,因此需要包含display()。它调用LIST,并引用list.h结构,因此需要main.h

是的,那些.h文件包含在main.c中;好点子。但是,如果main.c完全包含明确需要的内容,则代码将不那么笨拙(更专业)。

考虑到这一理念,这里是一个经过重新设计的main.h,没有多余的/*---main.c file---*/ #include <stdio.h> // printf() #include <conio.h> // getch() #include "list.h" // NodeDisplay(), LIST_T int main(void) { LIST_T pList = { .head = NULL }; /* Allocate & Insert a node into the list. */ NodeCreate(&pList, 100); NodeDisplay(pList.head); getch(); return(0); }

main.c

此版本的NodeCreate()包含所需内容,并适当调用 less primitive 函数。它不需要全局变量&#39;因为它根据需要将其本地存储传递给更原始的函数。

哦!你注意到函数main.c

虽然可以在list.c中执行分配和插入新列表节点的操作,但是这种操作很可能是与其他链接列表操作很好地匹配的常见事件。因此,将此功能添加到/*---list.c file ---*/ #include <stdio.h> // printf() #include <stdlib.h> // malloc() #include "list.h" // NODE_T, LIST_T void NodeDisplay(NODE_T *node) { printf("%d\n",node->a); return; } void NodeCreate(LIST_T *list, int a) { NODE_T *newNode = malloc(sizeof(*newNode)); if(NULL == newNode) { fprintf(stderr, "malloc(newNode) failed.\n"); goto CLEANUP; } if(NULL == list) { fprintf(stderr, "Passing NULL as the list address not allowed.\n"); goto CLEANUP; } /* Initialize new node fields (payload) */ newNode->a = a; /* Link newNode as new 'list head' node. */ newNode->next = list->head ? list->head->next : NULL; list->head = newNode; newNode=NULL; CLEANUP: if(newNode) free(newNode); return; }

main.c

因此可以从 less primitive list.h调用此函数,将函数的原型添加到/*---list.h file-------*/ #ifndef LIST_H #define LIST_H typedef struct NODE_S { int a; struct list *next; } NODE_T; typedef struct LIST_S { NODE_T *head; }; extern void NodeDisplay(NODE_T *node); extern void NodeCreate(LIST_T *list, int a); #endif

{{1}}

请参阅剧透代码 here