2012-01-09 58 views
2

我們在C的結構說在運行時如何從內存訪問C結構成員?

struct info{ 
    int no; 
    char first_name[20]; 
    char last_name[20]; 
    char status; 
} 

在運行時,當我們試圖通過他們的名字來訪問這些成員,說info_var.noinfo_var.first_name,或者我們用的指針結構,info_ptr->noinfo_ptr->first_name,如何這些個人會員訪問?

我的意思是,該結構將被存儲,通過與一些必要的填充沿着成員成員,但如何運行或可能的編譯器,如果更換髮生在編譯的時候,他們的名字訪問這些個人會員?

我知道有很多是依賴於實現的,但如果任何人都可以扔在任何實現一些輕或只是給出一個概述這將是非常好的。

回答

2

通過指針或對象訪問沒有區別,實際上info_ptr->no相當於(*info_ptr).no

實際的成員訪問權限是特定於編譯器的。

假設你有:

class A 
{ 
public: 
    char c; 
    int x; 
    A() {}; 
}; 

以下是訪問代碼:

A a; 
004113BE lea   ecx,[a] 
004113C1 call  A::A (4110E1h) 
    int y = a.x; 
004113C6 mov   eax,dword ptr [ebp-8] 
004113C9 mov   dword ptr [y],eax 

因此,編譯器,在這種情況下,生成二進制知道哪裏x被存儲在相對於內存a - 在A實例中有8個字節。這是因爲填充。

編輯:我剛纔看到,問題是關於C.不管,應該是相同的:)。

+0

你的代碼假定對象是本地的,它可能不會在大多數情況下。因此,你的答案是錯誤的,特別是如果指針本身是一個全局變量。看到我的答案。 – Lindydancer 2012-01-09 10:39:12

+0

@Lindydancer我懷疑這一點。在這個標準沒有說明的事情中,你不能說「這是錯誤的」。我可以編寫我自己的編譯器,它遵守標準並以我在這裏描述的方式訪問內存。沒有一條規則,我只是貼上了其中一個可能性。此代碼是由MSVC 2005在不帶優化的Win 32平臺下生成的。我指出它高度依賴於此。 – 2012-01-09 10:57:52

+0

這是錯誤的,因爲你使一般性陳述「訪問指針或對象沒有區別」。在這種特殊情況下,它不會,但在更常見的情況下,結構是一個全局變量,肯定會產生影響。事實上,作爲一名編譯器開發人員,我認爲這是一個「常見問題」,我認爲教人們通常與生成的代碼有很大不同是非常重要的。 – Lindydancer 2012-01-09 11:03:49

5

在C中,工作由編譯器完成。它將結構的數據成員編譯爲內存偏移並將它們應用於結構的基地址。

沒有爲變量名稱作爲e.g的Python

0

每個字段沒有動態查找已預先確定的從struct的起始位置的偏移。偏移量在編譯時確定。機器代碼只是將字段的偏移量從struct的地址添加到該字段的地址。

當你說「在運行時,當我們試圖通過他們的名字來訪問這些成員」,需要注意的是所有的工作具有與該名稱是在編譯時做的做的是非常重要的。

2

直接訪問結構和通過指針訪問結構有很大的區別。

如果你直接訪問它,代碼將直接訪問內存地址,使用簡化的彙編程序語法,一個虛構的建築。下面訪問的實施例中的構件status,其被存儲在偏移44在下面的結構:

MOVB varno+44, reg2 

在另一方面,如果將通過一個局部指針訪問,該指針將典型地被存儲在寄存器中。因此,代碼會看起來像:

MOVB 44[reg1], reg2 

最壞的情況是,如果指針本身是一個全球性的指針,那麼代碼必須先讀指針的值:

MOVL info_ptr, reg1 
MOVB 44[reg1], reg2 

編譯器可以在某些情況下,在執行多次訪問時緩存指針。但是,如果訪問是寫入(指針或字符),則編譯器必須假定指針本身可能已被更改並因此從內存中重新讀取它。

我強烈建議使用一個全局結構,如果你的應用程序只包含一個。

+0

編輯:補充說彙編語法是一個虛構的機器。 – Lindydancer 2012-01-09 11:07:21