我正在学习以专业的方式编写程序。就像,通过创建单独的.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中定义
谁能告诉我我做错了什么?我是否包括两次,因为我得到了重新声明错误?
答案 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
请注意pCurrent
和list.h
并非list.c
或list.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.h
和main.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 。