熟悉链接器的符号解析的进来帮忙看看啊。cout<

R9R9R9 2006-12-31 03:33:47
#include <iostream>
using namespace std;
int main()
{
extern char main;

cout<<hex<<int(main)<<endl;
//main不是一个函数地址么。例如是0x12345678。这样以char方式声明。输出的不就应该是0x78了么/
//为什么实际上它输出的是ox12345678地址上的前8位的内容.就是push %ebp的指令码0x55
system("pause");
return 0;
}
//main
0: 55 push %ebp
1: 89 e5 mov %esp, %ebp

我也问过一些大侠,但是我看的不太明白。希望大家讲的详细一些些啊
环境:XP+dev-c++
...全文
845 48 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
48 条回复
切换为时间正序
请发表友善的回复…
发表回复
blue_zyb 2007-01-11
  • 打赏
  • 举报
回复
int main()
{
extern char main;
cout<<hex<<int(main)<<endl;
return 0;
}
------------------------------
我也晕,我以为你上面给的就是这个例子,没有细看你把main弄成fun了

简单的说,就是int main()引入了一个函数符号main,而extern char main在相同的可见域又引入了一个不同类型的char main;出现了冲突和歧异;也就是在extern char main;后面如果出现对main符号的引用,就不知道到底是指main函数还是char main了。
R9R9R9 2007-01-11
  • 打赏
  • 举报
回复
int main()
{
extern char fun;
cout<<hex<<int(fun)<<endl;
return 0;
}这个是链接出错
----------------------------

int main()
{
extern char main;
cout<<hex<<int(main)<<endl;
return 0;
}
是编译出错,呵呵.而我觉的编译正确,而链接出错更合理一些啊.这跟上面的那个有什么区别嘛..晕:

到底编译器主要做了哪些工作啊.两位给俺讲一讲好么?

blue_zyb 2007-01-11
  • 打赏
  • 举报
回复
另外VC6. VC7都是链接出现错误
----------------------------
lz,应该是编译出错吧。。。
R9R9R9 2007-01-11
  • 打赏
  • 举报
回复
靠.搞到现在出现:

随便建立一个空的工程,链接都会出错

提示:文件名 目录名或卷标语法不正确

见鬼了
R9R9R9 2007-01-11
  • 打赏
  • 举报
回复
嗯...到此为止吧.谢谢你们两个.呵呵

to:blue_zyb()不好意思啊.过早结贴了.没分给你了..呵呵
blue_zyb 2007-01-10
  • 打赏
  • 举报
回复
我快晕死了...

我刚在mingw上测试,发现只有lz的特殊情况不会报错(也就是只有对main函数不出错)
而对于

void fun()
{
extern char fun;
cout<<hex<<int(main)<<endl;
}
就会报错

不知道lz的gcc上如何??
redleaves 2007-01-10
  • 打赏
  • 举报
回复
昨天就回了的.不过CSDN老出问题,数据库访问出错....

C++编译器放入对象文件的是经过name-mangling的符号.就你的这个问题而言,如果char main和int main()在不同的编译单元里,你就可以看出来,会产生符号未定义的错误.
在同一个编译单元里,原本应该编译出错的,但gcc通过了.这个符号是在编译时就解析了的,完全可以做到和name-mangling无关.因为编译时可做的工作远远多于链接时.而且就算是name-mangling过的符号,也可以反解析出来.至于如何实现,没有标准,自己想怎么做就怎么做.我猜测它是按旧C的方式来处理这个问题了.
R9R9R9 2007-01-10
  • 打赏
  • 举报
回复
另外vc7对于main的处理跟其他的任何符号也都是一样的。呵呵,所以这些各个编译器实现可能都不样的。我们讨论的这个问题,可能本身就是没有任何的意义的 =_=!




R9R9R9 2007-01-10
  • 打赏
  • 举报
回复
to :blue_zyb()

是啊,我也晕了,不过这样子出错更好,就相当于只声明了一个变量,没有定义,出错更符号情理
int main()
{
extern char fun;
cout<<hex<<int(fun)<<endl;
return 0;
}

另外VC6. VC7都是链接出现错误,也再次证明了redleaves(程序员)的观点,GCC是一个变态的编译器不管里面这边复杂的细节了.真是麻烦,呵呵
redleaves 2007-01-10
  • 打赏
  • 举报
回复
绝大多数的书不会讲这些细节的,而且不同的编译器,实现的细节也是不一样的,千差万别.
说实在,我自己以前也是边写边想的.反正只要能达到最终目的(完成标准的要求)就可以了.只要原理上明白就行,细节就自己发挥吧.
blue_zyb 2007-01-10
  • 打赏
  • 举报
回复
我不是这个意思:

int main()
{
extern char main;
cout<<hex<<int(main)<<endl;

return 0;
}
不出错对吧

但是这样就会出错:
void fun()
{
extern char fun;
cout<<hex<<int(fun)<<endl;
}

int main()
{
fun();
return 0;
}

照理说fun和main应该处于对等地位,要对一起对,要错一起错,这里却给了main特殊待遇...
至少在我的mingw g++上是如此,lz再试下上面我提供的fun例子

R9R9R9 2007-01-10
  • 打赏
  • 举报
回复
应该是这样的吧?
void fun();

int main(int argc, char *argv[])
{
//extern char main;
//cout<<hex<<int(main)<<endl;
fun();
system("PAUSE");
return EXIT_SUCCESS;
}
void fun()
{
extern char main;
cout<<hex<<int(main)<<endl;
}
我这里显示正常啊,还是55.呵呵

对了TO:redleaves(程序员),blue_zyb()
有没有哪本书,或者哪些资料讲编译,链接的过程讲的比较详细的啊.我找了一下,好像找不到啊.真是太复杂了, 这个编译器啊.

R9R9R9 2007-01-09
  • 打赏
  • 举报
回复
to: redleaves(程序员) 和 blue_zyb

首先谢谢你们两个的讨论,看了好久,又明白了很多东西,原先我不知道CSDN结贴后还能继续的回贴,所以一直没有留意这个贴子,今天不小心GOOGLE一下,才看到原来你们又进行了如此精彩的评论,让我学习了很多,谢谢你们:
--------------------------------------
另外to: blue_zyb

在redleaves(程序员)回复中:
问题是这句
extern char main;
这句肯定会造成符号重定义.当然,gcc这个变态支持这么写....

我原先以为redleaves(程序员)说的造成符号的重定义指的是"语言本身相关"的重定义,所以我后来回复他说,extern char main并不会造成符号的重定义。但后来我明白了,他所说的“符号重定义”指的是定义了两个同名不同意的"符号".这里的符号只是目标文件里的一个名称.和它是不是变量的声明/定义没有关系.

于是就有了我的回复:
谢谢您的指导,昨天想当然认为extern char main,只是声明了一个变量,所以就认为不会造成符号的重定义,我知道我错了。其实会生成一个extern 符号,也就是未定义的全局变量,是一个弱符号。所以链接的时候选择了main函数的这个强符号。

我这里指的弱符号,我的理解是这样的,extern char main声明了一个外部符号,而这个外部符号并没有初始化,所以我就按照:CS:APP中提到的弱符号的定义:未初始化的全局变量是一个弱符号,我就认为这个main是一个弱符号,然后再根据书中指出的强弱符号的三条Rules,判断链接器在看到main符号的时候,选择了函数main这个强符号,然后根据晨星老大提到的链接时的符号解析步骤,得出int(main)=0x55

--------------------------------------------------------------------
原先我以为整个过程就是这样的了,可是当我看到redleaves的回复:
至于C++中,由于有了name-mangling,就可以知道每一个变量(准确点说是对象)的类型,所以出现上述这种情形时,可以分辨出来。

我又迷糊起来了,到底放入符号表的符号是原始的main符号还是经过name-mangling的符号呢?
如果是原始的符号,那么name-mangling又有什么作用呢?
那如果是经过name-mangling后的符号,那么这char main与int main()这两个符号就是在符号表中表现出来的就是不相同的两个符号了,那么当看到语句cout<<hex<<int(main)<<endl时,它又是如何对main解析的呢?

谢谢你们的指导啊,我对这些一知半解的,如何有什么错误的,请指出来,我会改正的:


blue_zyb 2007-01-08
  • 打赏
  • 举报
回复
另外,如果你所说的"multiply-defined symbols"只是针对C里
int a;
int a;
这类情况.我想,它对C++是不适用的.因为C++里有"一次定义原则".在C++里,不可能有多个"定义"的选择问题.有的只是对符号名和它指向的符号实体的选择.
------------------------------------------------------
最后说的这段话倒是同意,可能我前面没有好好强调我说的那一套是在C语言中,失误,呵呵~

blue_zyb 2007-01-08
  • 打赏
  • 举报
回复
当然,如果你认定你所说的"multiply-defined symbols"选择问题不包括链接时的符号选择,那我也无话可说.
------------------------------
晕,我说的就是链接时的选择问题
我引用过的话:
Given this notion of strong and weak symbols, Unix linkers use the following rules for dealing with multiply-defined symbols:
是linkers,not compilers

但对符号的选择并不仅仅是局限在编译过程,在链接过程中对符号也要进行选择,而这种选择就表现为重定位.如果这个过程有符号冲突,也会表现为符号重定义.
-----------------------------------------------------
在C语言的前提下,
extern char main;是不会参加选择的,而只参与重定位。所以不会与main的实际定义发生“符号重定义”的冲突。
char main;是参与选择的;如果没被选上,它也会被重定位到main的真正定义,这倒是不假。

例如,假设a.c有:

void fun();
float x = 1.0; // initialized,strong symbol

int main()
{
fun();
return 0;
}

b.c有:

int x; // uninitialized,weak symbol
void fun()
{

printf("%x", x);
}

那么,由于b.c中的int x是弱符号,所以选择了a.c中的强符号float x。那么,最终,b.c中的x
会被重定位到float x的地址,但在本编译单元内,仍然作为int来解释。

所以,printf("%d", x);输出的并不是0,而是float 1.0 的int 解释。
redleaves 2007-01-07
  • 打赏
  • 举报
回复
另外,如果你所说的"multiply-defined symbols"只是针对C里
int a;
int a;
这类情况.我想,它对C++是不适用的.因为C++里有"一次定义原则".在C++里,不可能有多个"定义"的选择问题.有的只是对符号名和它指向的符号实体的选择.
redleaves 2007-01-07
  • 打赏
  • 举报
回复
如果你把符号的选择仅限定在编译过程中,而不包括链接.那的确如你所说.
但对符号的选择并不仅仅是局限在编译过程,在链接过程中对符号也要进行选择,而这种选择就表现为重定位.如果这个过程有符号冲突,也会表现为符号重定义.
实际上,在编译过程中,对于符号的选择也是类似的情况.只是定位的过程不是那么直接而已.

当然,如果你认定你所说的"multiply-defined symbols"选择问题不包括链接时的符号选择,那我也无话可说.

另外,至于你所说的C里的那些现象,是和C++有所不同.
在C里int a;只是尝试定义a,如果成功,则产生一个强符号,如果失败,则产生一个弱符号指向前面的定义.而且在多个文件中都定义了int a,那就会有多个强符号,最后会链接失败(这点上和C++相同).不过这是C99标准才改进的.旧的C则不是这样.只是,似乎只有gcc实现了这个特性.

至此,我想我们已经把这个问题说得很明白.至于在说法上是怎么样,我想那并不重要,只要大家心里知道这是怎么回事就可以了.和你讨论这个问题让我把这些又温习了一便,很不错~.呵呵^_^
blue_zyb 2007-01-07
  • 打赏
  • 举报
回复
而且我看你所说的内容,似乎认为声明不会引入符号....
你反复说"extern char main确实只是声明,构不成定义",那我很想知道,如果
// a.cpp
extern char a;
a = "c";
这里的extern char a;不引入符号,下面所用的a不会产生"符号"未定义么?
--------------------------------------------------------------------
我并没有说extern char a;没有引入符号,它引入了一个"引用"符号,就像我前面讲过几次的:
UNDEF is for undefined symbols, that is, symbols that are referenced in this object module but defined elsewhere.

但是,在C/C++语言中,该声明语句并不会引起在本编译单元中为之分配存储,而只是发表声明说:“其他文件中定义了一个叫a的对象,我想引用它,请链接器在链接的时候,把我所声明的a与实际的a定义关联起来。"

也就是说,在链接阶段,会把a.cpp中的a的地址重定位(reloation)为其他文件中为a分配的地址。比如b文件中有int a = 10; b编译单元为a分配了地址0x1000,在链接的时候a编译单元中的char a就与0x1000号地址相关联。


至少我认为它引入了符号,是个弱符号,并且对于符号实体的选择是在链接时完成的.也就是你所说的"multiply-defined symbols"的选择问题.
--------------------------------------------
如果你看了我的文字,我的阐述很明确,extern char main;不参与"multiply-defined symbols"的选择问题;而是在选择这一步骤以后,对extern char main中的main声明进行relocation。 char main; 才参与符号选择问题。


最后,我想说明的一点是: C 和 C++在处理强弱符号这一点上确实是有区别。像int c;这样的语句在C语言中是一个弱符号;所以如果另一个文件中有char c = 'a';链接时将不会报错而选择char c;在C++中则会报错。但我不确定C++中对强弱符号的具体划分,因为没有看过相关的资料...
blue_zyb 2007-01-05
  • 打赏
  • 举报
回复
不好意思,最后一句没写完就提交了...

所以,extern char main; 与main()函数的关键关系是 relocation,让char main指向main函数
而 char main; 与main()函数的关键关系是 "multiply-defined symbols"的选择
blue_zyb 2007-01-05
  • 打赏
  • 举报
回复
to:lz
其实会生成一个extern 符号,也就是未定义的全局变量,是一个弱符号。所以链接的时候选择了main函数的这个强符号。
----------------------------------------------
从你说的"链接的时候选择了main函数的这个强符号。"这种说法,可以看出涉及就是链接器对于"multiply-defined symbols"的选择问题,那么也应该契合CS:APP中所述的强弱符号的概念。如果你愿意的话,可以出来为你的术语“弱符号”正一下名 :)

假设你的弱符号与我所指的是同一概念,那么extern char main确实只是声明,构不成定义,所以不存在"multiply-defined symbols"的选择问题。这种"强弱符号选择"问题的例子是:
a文件中定义了main函数体,是一个强符号
b文件中定义了char main; (未初始化),是一个弱符号,那么链接的时候会根据
Rule 2: Given a strong symbol and multiple weak symbols, choose the strong symbol.
选择main函数这个强符号,而不会报错.

但如果在b文件中定义的是char main = 'a'; 也是强符号,那么由于
Rule 1:Multiple strong symbols are not allowed
链接器就会报错


回到你的问题,先把我上面摘过的一段话再抄一遍:
UNDEF is for undefined symbols, that is, symbols that are referenced in this object module but defined elsewhere. COMMON is for uninitialized data objects that are not yet allocated.

extern char main;声明了一个在其它文件中定义的main变量,在本文件的符号表中,它被放在UNDEF(比如在Unix系统下,其他系统类似,只不过名称细节有所不同).这和与弱符号概念相关的uninitialized data objects是不相同的,后者放在COMMON段。

等到链接器按照上面讲到过的的3个RULE解析完多符号的定义问题,并且没有出错后,必然有一个最终的main定义,然后链接器会对进行extern char main进行重定位(relocation),让它指向最后挑出的这个唯一的main定义。用CS:APP的话来说就是,
associated each symbol reference in the code with exactly one symbol definition

所以,extern char main; 与main()函数的关键关系是 relocation
而 char main;
加载更多回复(28)

65,184

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧