【发布时间】:2015-04-03 15:43:16
【问题描述】:
我正在使用 VS 并在 C 中使用我的第一块可重用代码,因此我将我的代码分成头文件和源文件,这会导致一些意外行为。
在我看来,不知何故,链接器无法解析我的 typedef 结构。我尝试将实际的结构声明移动到实现文件中,并从头文件中对结构进行类型定义,但没有成功。
为了简洁起见,我删除了所有实现,因为这不是问题。
// queue.h
#ifndef INC_QUEUE_
#define INC_QUEUE_
#include <stdint.h>
// STRUCT TYPEDEF
typedef struct QueueElement { ... } QueueElement;
typedef struct Queue { ... } Queue;
// FUNCTION PROTOTYPES
Queue* queue_construct();
uint32_t queue_peek(Queue *);
void queue_enqueue(Queue *, uint32_t);
uint32_t queue_dequeue(Queue *);
uint8_t queue_empty(Queue *);
void queue_destroy(Queue *);
#endif
// queue.c
#include <stdlib.h>
#include "queue.h"
Queue* queue_construct() { ... }
uint32_t queue_peek(Queue *queue) { ... }
void queue_enqueue(Queue *queue, uint32_t element) { ... }
uint32_t queue_dequeue(Queue *queue) { ... }
uint8_t queue_empty(Queue *queue) { ... }
void queue_destroy(Queue *queue) { ... }
源代码一切正常,都可以编译,但是当我尝试将其包含在例如这个文件...
#include <stdio.h>
#include "queue.h"
int main()
{
Queue *q = queue_construct();
queue_destroy(q);
return 1;
}
我的链接器一直给我的错误:
error LNK2019: unresolved external symbol "struct Queue * __cdecl queue_construct(void)" (?queue_construct@@YAPAUQueue@@XZ) referenced in function _main
error LNK2019: unresolved external symbol "void __cdecl queue_destroy(struct Queue *)" (?queue_destroy@@YAXPAUQueue@@@Z) referenced in function _main
任何帮助将不胜感激,这可能是一个愚蠢的问题,但正如我所说,我从未在 VS C 中处理过“更大/多文件”项目。
编辑
有人向我指出,包含 main 函数的源文件确实在 cpp 源文件中,但我的头文件和实现在 C 文件中。据我所知,您可以在 C++ 代码中的任何位置使用 C 文件,其中一个示例就是能够在 C++ 中使用任何 C 系统库。
该程序现在运行良好,但现在我的问题是:为什么我不能在 cpp 文件中使用 C 头文件?为什么会出现这种情况。显然我错过了一些重要的东西。
【问题讨论】:
-
似乎无法找到 queue.c 中的函数。你确定这个文件是你项目的一部分并且是和 main.c 一起构建的吗?
-
我会这么说。我有一个项目,其中包含 VS 为给定 C++ 项目创建的默认文件夹,我的 *.h 文件位于“头文件”文件夹中,源文件位于“源文件”文件夹中。
-
我看到的唯一一件事是结构名称和 typedef 是相同的。尝试将
typedef struct Queue { .... } Queue;更改为typedef struct queue_ { ....} Queue;我很难相信这是原因,但这是我唯一能看到的。这是假设 main.c 和 queue.c 都被编译和链接在一起。注:早在上个世纪(大约 1983 年),当我学习 C 时,有人告诉我要确保名称不同……不记得解释了,我只是一直这样做。 -
名称应该不同的原因是(回到何时)编译器内只有一个命名空间。现代编译器在跟踪具有相同名称拼写的不同关联方面要好得多。但是,结构定义应该有一个标签名称,而没有 typedef 名称。那么对结构定义的所有引用都应该是“struct tagName”。使用 struct tagName 在几个方面有帮助:代码更清晰/没有不必要/误导性的名称,编译器名称空间没有多余的条目,它是首选语法
-
看起来队列文件是用C编译的,主文件是用C++编译的
标签: c visual-studio struct header linker