把调试程序的时候的一些错误提示和解决方法记录下来,有备无患

从零开始,学习windows编程(6)–改换entry,link错误的简单分析
还是那个hello.c程序,我们将其小修改一下,来开始今天的话题。

    说明:在我们调试C语言的过程中,经常会遇到duplicate
symbol错误(在Mac平台下利用Xcode集成开发环境)。如下图:

1.symbol referencing errors

1 #include <stdio.h>
2
3  int myentry()
4 {
5     printf(“hello world”);
6     return 0;
7 }可以看到,我将原来main的位置换成了myentry,这会有什么结果发生呢?

澳门新葡萄京官网注册 1

undefined                        first referenced
 symbol                              in file
———                        —————-
_dot_asm                        
E:CCStudio_v3.1MyProjectsdot_mpy_6211Debugmain.obj
>>   error: symbol referencing errors

D: est>cl /c hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

    一.简单分析一下C语言程序的开发步骤。


hello.c

    澳门新葡萄京官网注册 2

提示找不到符号,一般是出现在用c调用汇编函数的时候,比较大的可能性是汇编程序里面的标号写错了(特别是前面少了一个下划线),或者是忘记将标号定义成全局的了(在文件开头用 
“.global 标号”的形式可以定义)

OK,没有问题,生成了hello.obj。

    由上图我们可以看出C语言由编写源程序->编译->链接->运行几个步骤进行。

     不过我碰到另外一种情况,是由于存在同名的文件.
    
比如说我的工程里面,有dot.c和dot.asm两个文件,分别定义了dot_c和dot_asm两个函数,这个时候就会有其中一个函数提示找不到了,经过检查,原来CCS在编译的时候,会根据文件名(不含扩展名)生成同名的目标文件(扩展名为obj),而我前面的两个文件,文件名相同而扩展名不同,那么在编译的时候,就会有一个生成的目标文件被另外一个覆盖的问题(取决于编译的顺序).知道了原因就好解决了,只要这两个文件的文件名不要相同就好了.

D: est>link hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

    编写源程序:

==========================================================

LIBC.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
hello.exe : fatal error LNK1120: 1 unresolved externals

    C语言的源文件的扩展名为.c,源文件以ASCII的形式存储,不能直接被计算机执行。

2.弹出一个确认框,提示”TRDX target application does not match emulation
protocol!Loaded program was created with an rtdx library which does not
match the target device”

link过程出现了问题,报了一个LINK2001错误。这个错误在MSDN上是这么说的:

    编译:


unresolved external symbol “symbol”

澳门新葡萄京官网注册,    1.把C语言源程序翻译成计算机可以识别的二进制代码,由编译器完成。

错误原因是使用的是软件模拟(Simulator),不能模拟JTAG

Code references something (such as a function, variable, or label) that
the linker cant find in the libraries and object files.

    2.编译的同时进行语法检查,如果发现语法错误,则编译失败。如果编译成功,生成扩展名为“.obj”的目标文件。

解决方法:打开cdb文件,选择”Input/Output -> RTDX-Real-Time Data
Exchange Settings”右键,然后选择”Properties”,打开对话框,RTDX
Mode的下拉列表中选择Simulator(默认值是JTAG,需要接仿真器才能用默认值)

Possible causes

    3.每个源文件是单独进行编译的,如果一个项目中有多个.c源文件,则会生成多个.obj目标文件。

What the code asks for doesnt exist (the symbol is spelled incorrectly
or uses the wrong case, for example).
The code asks for the wrong thing (you are using mixed versions of the
libraries, some from one version of the product, others from another
version).
This error message is followed by fatal error LNK1120.

    链接:

具体原因,其实结合前面几篇的知识,就可以很容易的推理出来。如果大家有兴趣,可以试着先推理一下,再看下面的分析过程,这样理解更深刻一些。

    1.将所有有关联的obj目标文件,及系统提供的C库函数等组合在一起生成可执行文件。

对于LINK错误,应该算是C/C++特有的,而且比较麻烦,难以理解和解决的一类错误。C语言还好一些,到了C++中,LINK错误常常会带一些“乱码”符号,就更让初次接触到的童鞋们摸不到头脑了。正好借这一个小例子,来看一下思路。

    2.生成的可执行文件的文件名与源程序文件名形同,计算机可以直接执行。

首先,我们使用cl从hello.c生成了hello.obj文件,由于没有加上/Zl选项,所以生成的hello.obj文件还是带有两个defaultlib的,一个为libc.lib,还有一个oldnames.lib。这样,在LINK的时候,会将hello.obj与libc.lib进行链接,而libc.lib是很多obj合在一起形成的,里面有crt0.c生成的名为crt0.obj文件。回想我们上次看到的crt0.c的源码文件,里面函数为mainCRTStartup,在mainCRTStartup函数中调用到main函数了,main函数这个external
symbol没有找到(其他函数如_heap_init。。。看来都是找到了),所以报出来一个LNK2001错误,告诉用户,main这个symbol没有找到,您把它忘哪儿啦。

    运行:

相关扩展

    双击即可运行生成的可执行文件。

link时使用/entry选项选定入口

   二.错误原因

D: est>cl /c hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

      源文件中引入的另一个源文件。

hello.c

      例如:在main.c中#include<test.c>

D: est>link /entry:myentry hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

   三.错误分析

LIBC.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
hello.exe : fatal error LNK1120: 1 unresolved externals

      由于编译的过程是对每个源文件单独进行编译的,如果单个源文件没有语法错误,编译就会通过。而链接过程是将所有有关联的obj目

其他不变,在link的时候加上/entry选项,结果还是和原来一样。因此,可以确定,link过程需要将所有的符号找到其所,而不像编译过程可以“打马虎眼”,即使是有一些external的也可以不理。另外,不管这个函数有没有“使用”到,都必须被link程序找到。这里的“使用”意思为执行过程中,执行到它。可以再看一个例子:

文件及系统的库函数组合在一起。而include预处理指令类似与代码的拷贝,并且C语言默认情况下不允许重复定义函数,因此引入的源文件

 1 #include <stdio.h> 2  3  int myentry() 4 { 5     printf(“hello
world”); 6     return 0; 7 } 8  9 int main()10 {11     myentry();12 }13
14 int test()15 {16     nofunc();17     return 0;18
}从上面的代码可以看到,在默认编译链接的情况下,test函数是没有被调用到的,而其中的nofunc函数是没有定义的。我们来对其做一下编译链接。

中函数在链接时会报重复定义的错误。也就是我们看到的duplicate
symbol错误。

D: est>cl /c hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

    
小伙伴们,以后要注意了,在C语言开发中,不允许在源文件中引入其他的源文件,只可以引入头文件呦! 

hello.c

      

D: est>link hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

hello.obj : error LNK2001: unresolved external symbol _nofunc
hello.exe : fatal error LNK1120: 1 unresolved externals

可以看到,link的时候,找不到nofunc这个symbol,从而报错。

这也是C/C++的一个比其他语言麻烦的地方,有编译时、链接时和运行时的划分,这样子清晰了,但是概念也多了,如果再加上隐藏了一些东西的实现和原理,理解起来就更不容易了。

使用/Zl选项

如果对myentry代码使用/Zl选项。

D: est>cl /c /Zl hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08
for 80×86
Copyright (C) Microsoft Corporation.  All rights reserved.

hello.c

D: est>link hello.obj
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

LINK : fatal error LNK1561: entry point must be defined

此时,则出现LNK1561错误。MSDN上对应的解释为:

entry point must be defined

The linker did not find an entry point. You may have intended to link as
a DLL, in which case you should link with the /DLL option. You may have
also forgotten to specify the name of the entry point; link with the
/ENTRY option.

Otherwise, you should include a main, wmain, WinMain, or wMain function
in your code.

If you using LIB and intend to build a .dll, one reason for this error
is that you supplied a .def file. If so, remove the .def file from the
build.

因为/Zl去掉了defaultlib,所以link直接就是hello.obj,而不会去链接libc.lib,因为默认定义的entry
symbol为mainCRTStartup,此时没有libc.lib,里面的mainCRTStartup也就没有,所以会提示出没有定义entry
point错误。

Way1:

照MSDN上面的解释,我们再来将main函数使用上,然后做编译/Zl,以及链接工作会怎样呢?

首先将myentry改为main。之后:

D: est>cl /c /Zl hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

hello.c

D: est>link hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

hello.obj : error LNK2001: unresolved external symbol _printf
LINK : error LNK2001: unresolved external symbol _mainCRTStartup
hello.exe : fatal error LNK1120: 2 unresolved externals

此时的错误又不相同,这里出现寻找不到printf和mainCRTStartup的链接错误。

Way2:

将/entry选项指定为myentry。

D: est>cl /c /Zl hello.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

hello.c

D: est>link /entry:myentry hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

LINK : fatal error LNK1221: a subsystem cant be inferred and must be
defined

又出现一个新错误,LNK1221。来看看解释:

a subsystem can’t be inferred and must be defined

The linker does not have enough information to infer which subsystem you
will target your application.

To fix this error, use the /SUBSYSTEM option.

看来link的时候,还可以根据搜到的symbol以及定义的entry来自动判断编译出来的目标应用的subsystem,关于subsystem,似乎只有windows下面有这个编译选项,加上来再看一下。

D: est>link /entry:myentry /subsystem:console hello.obj
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

hello.obj : error LNK2001: unresolved external symbol _printf
hello.exe : fatal error LNK1120: 1 unresolved externals

OK,当加上之后,也出现了LNK2001错误,比上面要少一个_mainCRTStartup,还需要一个_printf。

Way3:

而综合上面两种方法,将way1和way2合起来使用,使用main函数代替掉myentry的源码,然后将main设置entry
point。<

还是那个hello.c程序,我们将其小修改一下,来开始今天的话题。 1 #include
stdi…