&引用;“已定义”;VC+中的错误+;

&引用;“已定义”;VC+中的错误+;,c,data-structures,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

我正在学习以专业的方式编写程序。例如,通过创建单独的.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();

}
/*--list.h文件-------*/
#ifndef列表
#定义列表
结构列表{
INTA;
结构列表*下一步;
};
typedef结构列表;
列表*pHead=NULL,*PCCurrent=NULL;
作废显示(作废);
#恩迪夫
/*---list.c文件---*/
#包括“main.h”
无效显示()
{
pHead->a=100;
printf(“%d”,pHead->a);
}
/*----main.h文件-----*/
#ifndef MAIN_H
#定义主
#包括
#包括“list.h”
#恩迪夫
/*---main.c文件---*/
#包括“main.h”
真空总管(真空)
{
列表*新=pHead;
显示();
printf(“\n\n%d”,新建->a);
getch();
}
当我编译代码时,我得到以下错误 1> main.obj:错误LNK2005:_plist.obj中已定义电流 1> main.obj:错误LNK2005:_pHead已在list.obj中定义

谁能告诉我我做错了什么?我是否两次包含某个内容,因为这会导致重新声明错误?

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

这:

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

这是因为您在标题中定义内容,而不仅仅是声明它们

这:


意味着每个包含列表头的C文件都试图创建两个全局变量。然后,当您将这些C文件链接在一起时,这些变量会发生冲突。这是坏的,你不应该这样做。永远不要在头文件中定义对象。

您在头文件中定义了对象,然后将其包含在多个源文件中,从而打破了规则


如果要创建可跨不同转换单元使用的全局变量,则应。

您在头文件中定义了对象,然后将其包含在多个源文件中,从而打破了原有的规则


如果您想创建可以跨不同翻译单元使用的全局变量,您应该。

一般来说,
.c
文件包含变量、函数等的具体体现。;而
.h
文件包含变量、函数等的原型,可以在它的配套
.c
文件中找到

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

当考虑如何将代码拆分为单独的文件时,重要的是要考虑哪些函数、结构和宏是最原始的。例如,如果您编写两个函数,并且函数“a”调用函数“b”,则函数“b”是最基本的

其思想是将函数分组到一个“c”文件中,该文件是相关的,并且处于类似的原始级别

对于这个问题,更原始的列表函数应该体现在
list.c
中。然后,“list.h”用于原型化其他较原始的
.c
文件(如
main.c
)所使用的函数和结构

最原始的函数也是最自给自足的。虽然较低级的函数应该调用较低级的函数,但反之则会导致代码流笨拙

现在回顾问题代码:

/*---list.c file ---*/
#include "main.h"
list.c
应该被认为比
main.c
更原始。因此,拥有
list.c
include
main.h
(专业上)不是一个好主意<代码>列表.c,更原始应该更自给自足

与其包含
main.h
,不如让
list.c
包含自己的
list.h
,这样它就可以访问自己的“struct list”定义,等等

void display()
{
    pHead->a=100;
    printf("%d",pHead->a);
}
为了更好地隔离
list.c
,上述函数不应引用“全局”变量(pHead)。相反,最好将“要显示的节点”作为参数传递到函数中

考虑到这一点,下面是如何改进“list.c”和“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;
   } 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;
   }
单独来看,main.h需要
stdio.h
list.h
的目的是什么?如果删除了它们,在“main.h”中是否会有“未定义”的内容?也许这两个包含文件并不真正属于
main.h
。“但如果它们被从main.h中删除,为什么还要有main.h?”这是一个很好的观点。也许
main.h
没有任何作用,甚至不应该存在

main.c
文件是所有文件中最基本的文件,通常不应将任何内容导出到其他(更基本的)文件

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

是的,那些.h文件包含在
main.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);
   }
/*---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
为了从较不原始的
main.c
调用此函数,请将此函数的原型添加到
list.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);
   }
/*---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


参见扰流板代码。

一般来说,
.c
文件包含变量、函数等的具体体现。;而
.h
文件包含变量、函数等的原型,可以在它的配套
.c
文件中找到

通常情况下,变量和函数体不放在
.h
文件中;仅变量和函数原型
/*---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;
     }
/*---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