2013-03-10 252 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