2013-03-10 195 views
2

为什么这个工作?我认为全局数据在编译时被“初始化”(编译器以obj文件格式将空字节保存到.global部分,所以当部分被加载到内存中时,它被初始化为空)。那么如果编译器不知道函数将在运行时在内存中的什么位置,那么如何初始化指向函数地址的指针呢?C++ - 功能全局指针

#include <iostream> 

void vypis(); 

int neco; 
int * bla = &neco; 
void (*vypis_ptr)() = vypis; 

int main(int argc, const char * argv[]) 
{ 

} 

void vypis() { 

} 
+1

你确定编译器在困扰这些吗?主要没有任何东西,所以它没有任何关系,所以它不需要包含任何有问题的代码。 – 2013-03-10 11:01:14

+1

@PhilH,肯定它必须,vypis_ptr是一个外在的可见对象。 – 2013-03-10 11:02:03

+7

这种地址解析不一定是由编译器完成的,而是由加载器完成的。在程序启动之前完成的唯一重要的事情。此外,至少在理论上这些事情对于C和C++来说是不同的。在C++中,这甚至可以是一个构造函数,它会在程序启动之后但在进入'main'之前运行。 – 2013-03-10 11:03:29

回答

4

我删除冗余包括iostream让你的源实际上编译C和汇编它在我的系统上的可执行文件名为vypis。以下是我发现:

$ nm vypis | fgrep vypis 
00000000004004d0 T vypis 
0000000000600888 D vypis_ptr 

所以,vypis,一个功能,就是“文本”部分,vypis_ptr在全球,指向一个功能,就是“数据”部分中的一个全球性的。

数据部分中的对象具有存储在可执行文件中的值,我可以通过将objdump中的数据部分倾出来读取vypis_ptr中的内容。

$ objdump -d -j .data vypis 

vypis:  file format elf64-x86-64 


Disassembly of section .data: 

0000000000600878 <__data_start>: 
     ... 

0000000000600880 <__dso_handle>: 
     ... 

0000000000600888 <vypis_ptr>: 
    600888:  d0 04 40 00 00 00 00 00        [email protected] 

0000000000600890 <bla>: 
    600890:  a8 08 60 00 00 00 00 00        ..`..... 

在这里我们可以看到,值4004d0存储在vypis_ptr,但这是完全一样的显示在nm输出vypis位置。

+0

thx,我将研究这些实用程序 – Krab 2013-03-10 11:37:16

+0

hm但为什么有我的变量名称在obj文件? – Krab 2013-03-10 11:38:28

+0

@Krab因为它们是全局的并且使它们可见(通过未声明它们为“static”),所以它们可以导出并用于其他编译模块。并且名称需要在那里以便链接器可以找到符号。 – 2013-03-10 11:41:09