BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #92953同步于 2016/8/4
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

符号表是什么东西啊,有没有同学通俗一点儿解释一下

Gewter
2016/8/4镜像同步20 回复
百度了挺多,有点儿懵逼 主要是const修饰的变量,然后存到符号表里面。然后这个符号表是干啥用的呢?都存了啥啊
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
nuanyangyang机器人#1 · 2016/8/4
首先这已经超出C语言的范畴了,这是链接器、装载器的概念。 c语言的程序可以分模块编译,然后链接在一起(静态链接)。有时候,一个模块需要引用另一个模块中定义的全局变量或者函数。但是,两个模块是分别编译的。编译器会遇到一个问题。以函数调用为例,如果模块A.c里的函数f调用了模块B.c里的函数g,那么:编译器在编译A.c的时候,只知道f试图调用g,但并不知道g在哪个模块里定义。 解决方案就是: 1. 编译A.c的时候,遇到调用g的地方,先把调用的目标空着,并在生成的目标文件(A.o)里写一个重定位记录(relocation entry):“f函数里xxxx位置试图调用g,请在链接的时候把地址填上”,同时在A.o的符号表里写一条:“我需要g,但不知道g在什么地方”。 2. 编译B.c的时候,发现有g的定义,就在生成的目标文件(B.o)里的“符号表”里放一个符号(symbol):“g在当前文件里的yyyy位置”。 然后,链接器拿到A.o和B.o,发现:A.o里有人需要g但不知道在哪里,B.o里有g。于是,就根据A.o里的那个重定位记录,把A.o里的代码修改一下,把g的地址填进去。 所以,这就是符号表:符号表里面包括很多符号(就是函数的名字和全局变量的名字等),以及每个符号的地址:可以是“已知地址”,也可以是“未知地址,需要从别的模块里解析”。 当然,现在的链接器还支持运行时的动态链接。这就需要符号表不仅仅要在编译时保存留给链接器用,即使编译好的可执行文件(exe)和动态链接库(dll、so、dylib)也要保留符号表和重定位记录。这样,在运行一个exe的时候,装载器会把它依赖的dll也装载进来,然后通过符号表,把exe/dll之间互相的引用填好。然后程序就可以执行了。
kingsleynj机器人#2 · 2016/8/4
谢谢暖女神! 这应该就是常量折叠的意思吧?网上有帖子说const常量在c里面不能用来定义数组: const int a = 5; int array[a] = {0}; 这种,而在c++里面可以。vs我试过了,不可以。而在xcode里面可以,另外xcode里面c++中语句(比如for)变量是局部的,而vc6.0中会说重定义,那么vc现在也不符合时代了吗。 【 在 nuanyangyang (暖羊羊) 的大作中提到: 】 : 首先这已经超出C语言的范畴了,这是链接器、装载器的概念。 : c语言的程序可以分模块编译,然后链接在一起(静态链接)。有时候,一个模块需要引用另一个模块中定义的全局变量或者函数。但是,两个模块是分别编译的。编译器会遇到一个... : ...................
nuanyangyang机器人#3 · 2016/8/4
【 在 kingsleynj 的大作中提到: 】 : 谢谢暖女神! : 这应该就是常量折叠的意思吧?网上有帖子说const常量在c里面不能用来定义数组: 没有一点关系。“常量折叠”发生在编译阶段,而“符号表”是编译的产物。 : const int a = 5; 如果这个可以编译通过的话,可能和C++11放宽了数组大小的条件有关吧。C++对于编译器的要求比C更高。有可能新版C++的编译器可以推断出“因为a是常量,所以可以用a的大小来定义数组长度”。 符号表里可能会有a这个项目,但存的是a的地址,目的是如果别的模块里想要访问这个全局变量a的值,链接器也要让它能够访问。 : ...................
nuanyangyang机器人#4 · 2016/8/4
【 在 kingsleynj 的大作中提到: 】 : 谢谢暖女神! : 这应该就是常量折叠的意思吧?网上有帖子说const常量在c里面不能用来定义数组: : const int a = 5; : ................... 另外vc6.0是我上小学的时候玩的。不知道你那时候出生了没有。所以别玩vc6.0了。
kingsleynj机器人#5 · 2016/8/4
?再次谢谢 可以再问一个问题吗?传引用和传指针到底有没有区别啊?引用和指针本身自然是有区别的,可是通过查看汇编代码,其实感觉传引用和传指针本身是没有区别的吧?传指针实现上还是和传值方式一样,会有一个临时变量的拷贝吧,引用呢?感觉看了很多博客,还是理不清二者的区别 【 在 nuanyangyang (暖羊羊) 的大作中提到: 】 : 没有一点关系。“常量折叠”发生在编译阶段,而“符号表”是编译的产物。 : ...................
nuanyangyang机器人#6 · 2016/8/4
【 在 kingsleynj 的大作中提到: 】 : ?再次谢谢 : 可以再问一个问题吗?传引用和传指针到底有没有区别啊?引用和指针本身自然是有区别的,可是通过查看汇编代码,其实感觉传引用和传指针本身是没有区别的吧?传指针实现上还是和传值方式一样,会有一个临时变量的拷贝吧,引用呢?感觉看了很多博客,还是理不清二者的区别 本质上没有区别。 C++里,一个重要的概念是object,不是“面向对象”的对象,是“存储空间”的意思。基本上,凡是有名字的东西都有存储空间。比如int a;,定义一个存储空间,名字叫a。但42就没有,它只是值。但如果a=42,那么意思是把42存储到a对应的存储空间里。现在a的存储空间里储存着42。 指针是对存储空间的引用(C++规格书的原话)。比如int *p = &a;,那么p里面存着一个指针,它指向a的存储空间。 C++的表达式的值分为左值(l-value)和右值(r-value),其中左值是对应存储空间的,而右值就不对应。所以,a是左值,而42是右值。至于p,p这个名字本身对应着存储空间,里面存着一个指针。所以p也是左值。表达式(*p)也是左值。意思是“p指向的那个存储空间”。(*p)和a对应的存储空间是一样的。 因为指针也是值,所以,你可以把p的值传来传去。然后再用(*p)这样的表达式操作a的存储空间。这是指针的工作原理。 总结一下:C++里,用int a;这种方法定义的标识符a对应存储空间,类型就是int。存储空间里存储值。指针本身是一种值,它指向存储空间。(*p)这个表达式对应的存储空间就是p指向的存储空间。 然后再说C++里的“引用”。 如果用int &b = a;这种方式定义,那么b这个标识符的存储空间和a的存储空间是一样的。 就是这么简单。b并没有自己的存储空间,可以认为b就是a这个空间的别名。 “引用”一旦定义,你就不能让b再去“指向”别的存储空间——在写下int &b = a;的时候,b的存储空间就固定了。 但是“指针”则不然。如果定义int *p = &a;,那么p本身是个存储空间,里面存着一个指针。你可以再找另一个指针,存到p里。比如 int c; p = &c; 这样p就指向c的存储空间了。 所以,区别就是“指针本身是一个值,这个值执行一个存储空间;但引用只是另一个存储空间的别名而已,本身并不是单独的值”。 以上是指针和引用的语义。C++编译器只要能实现这个语义,想怎么实现都可以。比如,如果int a; int &b=a;,b和a在同一个函数里,编译器最直接的做法就是把所有提到b的地方换成a。反正它们是相同的存储空间。 但是,如果把一个左值传给函数,比如 void foo(int &x) { x = x + 1; } void bar() { int a = 9; foo(a); } 这个时候发生的是:在foo里,x会有和bar里的a一样的存储空间。foo里对x进行了赋值,因为x和a的存储空间是一样的,foo会影响到bar里a里存的值,调用完foo(a),a里面存的值就是10了。 如果考虑编译器应该如何实现这个函数,那么其实还是有好多种方法的。比如, - 最朴素的就是让x用“指向a的指针”来表示,bar把a传给foo时,实现成(1)把a分配在内存里,而且(2)传a的地址。(这好像是我第一次提到地址) - 另一种实现方法是把foo“内联”(inline)到bar里面去。这时候,bar在编译器看来就好像是: void bar() { int a = 9; { int &x = a; x = x + 1; } } 按照语义,x=x+1会改变a里存的值,因为存储空间一样。编译器可以很聪明地把所有的x都替换成a来实现。而且,a也不用分配到内存里了:反正又没有人取它的地址,直接分配到寄存器里就行了。
zhaoyu1999机器人#7 · 2016/8/5
【 在 nuanyangyang 的大作中提到: 】 : 首先这已经超出C语言的范畴了,这是链接器、装载器的概念。 : c语言的程序可以分模块编译,然后链接在一起(静态链接)。有时候,一个模块需要引用另一个模块中定义的全局变量或者函数。但是,两个模块是分别编译的。编译器会遇到一个问题。以函数调用为例,如果模块A.c里的函数f调用了模块B.c里的函数g,那么:编译器在编译A.c的时候,只知道f试图调用g,但并不知道g在哪个模块里定义。 : 解决方案就是: : ................... 赞美暖神
jackling机器人#8 · 2016/8/5
赞美暖神 发自「贵邮」
kingsleynj机器人#9 · 2016/8/5
简直讲解的太好了,从"object"的概念,到左值/右值,到指针和引用本来的意思,再到传参时候的细节,完美解决了我想了很多天的一个问题啊! 啦啦啦,我爱暖女神! 【 在 nuanyangyang (暖羊羊) 的大作中提到: 】 : 本质上没有区别。 : C++里,一个重要的概念是object,不是“面向对象”的对象,是“存储空间”的意思。基本上,凡是有名字的东西都有存储空间。比如int a;,定义一个存储空间,名字叫a。但42就没有,它只是值。但如果a=42,那么意思是把42存储到a对应的存储空间里。现在a的存储空间里储存着42。 : ...................