linking... *** ERROR L104: MULTIPLE PUBLIC DEFINITIONS SYMBOL: TIMER0_HANDLER MODULE: main9.obj (MAIN9) *** ERROR L104: MULTIPLE PUBLIC DEFINITIONS SYMBOL: MAIN MODULE: main9.obj (MAIN9) *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS SEGMENT: ?PR?MAIN?MAIN9 *** WARNING L5: CODE SPACE MEMORY OVERLAP FROM: 000BH TO: 000DH *** ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL SYMBOL: MAIN MODULE: D:\KILE51\C51\LIB\C51S.LIB (?C_INIT) ADDRESS: 08A0H Program Size: data=31.0 xdata=0 code=663 Target not created是什么意思
时间: 2025-07-19 19:35:43 浏览: 4
<think>我们正在处理一个51单片机项目的编译链接错误。错误信息如下:
*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS
SYMBOL: TIMER0_HANDLER
MODULE: main9.obj (MAIN9)
*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS
SYMBOL: MAIN
MODULE: main9.obj (MAIN9)
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
SEGMENT: ?PR?MAIN?MAIN9
*** WARNING L5: CODE SPACE MEMORY OVERLAP
FROM: 000BH
TO: 000DH
*** ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL
SYMBOL: MAIN
MODULE: D:\KILE51\C51\LIB\C51S.LIB (?C_INIT)
ADDRESS: 08A0H
Program Size: data=31.0 xdata=0 code=663
Target not created
我们需要解释这些错误和警告的含义,并给出解决方案。
### 错误分析:
1. **ERROR L104: MULTIPLE PUBLIC DEFINITIONS (TIMER0_HANDLER 和 MAIN)**
- 这个错误表示同一个符号(函数或变量)在多个地方被定义为public(全局可见)。链接器发现了重复的定义。
- 对于`TIMER0_HANDLER`:可能是中断服务函数的名称。可能在一个项目中,这个函数被定义了两次(比如在两个不同的源文件中),或者同一个源文件被多次包含。
- 对于`MAIN`:主函数`main()`被重复定义。通常一个项目只能有一个main函数。
2. **WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS**
- 这个警告表示有一个函数(段)从未被调用过。链接器在覆盖处理时忽略了它。这里指出的段是`?PR?MAIN?MAIN9`,这通常与主函数相关。但是,注意这个警告的段名可能是主函数,而主函数本应由启动代码调用,所以这个警告可能是由于主函数定义问题引发的连锁反应。
3. **WARNING L5: CODE SPACE MEMORY OVERLAP**
- 代码空间内存重叠。链接器发现代码段在内存地址000BH到000DH处发生了重叠。这可能是由于中断向量表与代码段发生了重叠。在51单片机中,中断向量表从0003H开始,每个中断向量占8个字节。例如,外部中断0在0003H,定时器0中断在000BH。这个警告提示000BH到000DH有重叠,可能是在000BH处(定时器0中断向量)放置了代码,但这段代码与后面的代码发生了重叠。
4. **ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL**
- 这个错误表示有一个错误的符号引用。这里,库文件`C51S.LIB`中的`?C_INIT`(初始化代码)引用了`MAIN`,但是`MAIN`符号有错误(由于前面的重复定义错误导致)。
5. **Target not created**
- 由于存在错误,目标文件(可执行文件)没有生成。
### 解决方案:
1. **解决重复定义问题(L104错误)**:
- 检查项目中所有源文件,确保`TIMER0_HANDLER`函数只在一个地方定义。如果它在头文件中定义,应改为在源文件中定义,并在头文件中用`extern`声明。
- 确保`main()`函数只在一个源文件中定义。通常整个项目应该只有一个`main()`。
2. **处理未调用段警告(L16)**:
- 这个警告可能是由于重复定义导致主函数没有被正确识别。先解决重复定义问题,这个警告可能会消失。
3. **解决代码空间重叠(L5)**:
- 检查中断向量表。在51单片机中,定时器0的中断向量地址是000BH。确保在000BH处放置的是跳转到中断服务程序的指令(如`LJMP TIMER0_HANDLER`),并且这条指令占3个字节(000BH, 000CH, 000DH)。如果中断服务程序的地址超过了000DH,则可能与后面的代码重叠。需要确保中断向量表后的代码从0013H(下一个中断向量)开始,或者中间有足够的空间。
- 另一种可能是链接器脚本或内存配置错误,但51单片机通常使用固定地址。检查启动代码(STARTUP.A51)是否正确配置了中断向量表。
4. **解决L118错误**:
- 这个错误是由前面的错误引起的,解决L104错误后,这个错误应该会消失。
### 步骤总结:
1. 检查所有源文件,解决重复定义的`TIMER0_HANDLER`和`main`函数。
2. 确保中断向量表正确设置,特别是定时器0的中断向量(000BH)处应有一条跳转指令,且该指令不会与后续代码重叠。
3. 重新编译链接,看是否还有错误。
### 示例代码结构:
在包含主函数的文件中:
```c
#include <reg51.h>
// 声明中断服务函数(如果定义在其他文件中,则用extern)
void Timer0_ISR(void) interrupt 1; // 定时器0中断服务程序
void main() {
// 主函数代码
}
```
在定义中断服务函数的文件中(比如timer.c):
```c
#include <reg51.h>
void Timer0_ISR(void) interrupt 1 {
// 中断处理代码
}
```
注意:不要在两个文件中都定义`Timer0_ISR`函数。
§§相关问题§§
1. 在51单片机项目中,如何正确声明和定义中断服务函数以避免重复定义?
2. 51单片机的中断向量表结构是怎样的?如何避免代码与中断向量表重叠?
3. 当出现“Target not created”时,如何根据Keil编译器的错误信息定位问题?
4. 在Keil C51中,如何处理多个源文件中的全局变量以避免链接错误?
5. 为什么在51单片机项目中需要特别注意中断服务函数的编写和链接?</think>### Keil C51编译错误解析及解决方案
#### 错误含义分析:
1. **L104: MULTIPLE PUBLIC DEFINITIONS**
- `TIMER0_HANDLER`和`MAIN`被重复定义
- 根本原因:
- 同名函数/变量在多个文件中定义为`public`
- 头文件未用`#ifndef`宏保护导致重复包含
2. **L16: UNCALLED SEGMENT**
- 警告:存在从未被调用的函数(此处是`MAIN`相关代码段)
3. **L5: CODE SPACE MEMORY OVERLAP**
- 代码段地址冲突(000BH-000DH是**定时器0中断向量地址**)
- 典型原因:
- 中断服务函数未正确定义
- 启动文件(startup.a51)与用户代码冲突
4. **L118: REFERENCE TO ERRONEOUS EXTERNAL**
- 因`MAIN`定义错误导致库文件`C51S.LIB`引用失败
5. **Target not created**
- 上述错误导致最终可执行文件未生成
---
#### 完整解决方案:
**1. 修复重复定义问题**
```c
// 方案1:在头文件中使用条件编译
#ifndef __TIMER_H__
#define __TIMER_H__
extern void TIMER0_HANDLER(void); // 声明为extern
#endif
// 方案2:在源文件中正确定义
void TIMER0_HANDLER(void) interrupt 1 {
// 中断处理代码
}
```
**2. 解决中断向量冲突**
修改启动文件`startup.a51`:
```assembly
ORG 0000H
LJMP MAIN ; 复位向量跳转到主函数
ORG 000BH ; 定时器0中断向量地址
LJMP TIMER0_HANDLER ; 指向中断服务程序
```
**3. 确保主函数正确定义**
```c
void main(void) { // 必须为void参数
EA = 1; // 开启总中断
while(1) { // 必须有主循环
// 用户代码
}
}
```
**4. 工程配置检查**
- 移除重复的源文件引用
- 确认仅包含一个`main()`函数文件
- 检查"Options for Target" → "Target"中内存设置是否冲突
---
#### 关键注意事项:
1. 中断函数必须:
- 使用`interrupt`关键字声明
- 放置在正确的向量地址(000BH对应定时器0)
2. 所有全局函数在头文件中用`extern`声明
3. 使用`STARTUP.A51`初始化堆栈指针
> **验证方法**:
> 编译后查看`M51`映射文件,确认:
> - `MAIN`和`TIMER0_HANDLER`地址无冲突
> - 中断向量表正确跳转
阅读全文
相关推荐


















