簡體   English   中英

內存地址可以在 C 中移植嗎?

[英]Are memory addreses portable in C?

假設我們有程序 1...

./程序1

int main(int argc, char *argv[])
{
  int *i;
  *i = 10;
  printf("%lld", i);
  return 0;
}

現在程序2...

./program2 program1output 10

int main(int argc, char *argv[])
{
  int *t;
  t = (int*)atoll(argv[1]);
  *t = atoi(argv[2]);
  return 0;
}

這會起作用嗎? 你可以在不同的程序之間共享內存地址嗎?

這種行為不是由 C 標准定義的。 在任何通用多用戶操作系統上,每個進程都有自己的虛擬地址空間。 除了某些共享內存外,分配給進程的所有內存都與分配給其他進程的內存分開:

  • 只讀數據可能會在進程之間共享,尤其是運行同一可執行文件的兩個進程的指令和常量數據以及共享庫的指令和常量數據。 該數據可能在不同的進程或不同的地址中具有相同的地址(取決於各種因素,包括代碼是否與位置無關以及是否使用地址空間布局隨機化)。
  • 默認情況下,一些操作系統還將系統范圍的共享數據映射到進程中。
  • 通過顯式請求進程映射共享內存段,可以在進程之間共享內存。 這些段可能會或可能不會出現在不同進程中的相同虛擬地址處。 (映射共享內存的請求可能會請求某個地址,在這種情況下,不同的進程可以安排使用相同的地址,也可以讓映射軟件選擇地址,在這種情況下,不同的進程不能依賴於接收相同的地址分配.)

在專用操作系統中,不同的進程可以共享一個地址空間。

補充

這不是正確的代碼:

int *i;
*i = 10;

聲明int *i; i定義為指針,但不為其分配值。 然后使用*i是不合適的,因為它試圖引用i指向的位置,但i沒有被分配指向任何東西。

要定義一個int並使其地址在輸出中可見,您可以定義int i; 然后打印&i

這不是打印地址的正確方法:

printf("%lld", i);

要打印地址,請將其void *轉換為void *並使用%p對其進行格式化。 格式化的結果是實現定義的:

printf("%p", (void *) &i);

這不是重建地址的好方法:

int *t;
t = (int*)atoll(argv[1]);

printf ,類型應該是void * ,並且嘗試使用atoll進行轉換時會出現問題。 C 標准不保證它會起作用; %p打印產生的格式可能不是正常的整數格式。 相反,將%p說明符與sscanf

void *temp;
if (1 != sscanf(argv[1], "%p", &temp))
    exit(EXIT_FAILURE);
int *t = temp;

當地址來自其他進程時, sscanf轉換的行為不是由 C 標准定義的。

原則上,應用程序在其自己的/私有內存上運行。 有多種方法可以在不同的進程之間共享內存,但這需要特殊的機制來克服上述“主要”(例如內存映射文件)。 有在短期看,例如, 文章共享內存。

在您的情況下,程序一將結束並且其內存不再可用; 並且您訪問它的方式絕對不是訪問共享內存所需的“特殊機制”之一:

盡管整數值可以轉換為指針值,但僅當整數值最初從指針轉換為有效對象時,訪問該指針才有效。 在您的示例中情況並非如此,因為在t = (int*)atoll(argv[1]);計算的積分值t = (int*)atoll(argv[1]); 從未指向當前程序中的有效對象。

通常,內存地址與進程相關聯,因為每個進程可能有自己的內存空間。 因此,地址是虛擬地址而不是物理地址,這意味着它們是對進程內存空間中某個位置的引用,而不是對芯片上某個位置的引用。

(並非所有環境都有虛擬內存。例如,嵌入式系統可能沒有。)

如果有兩個程序在同一個進程中運行,則可以在它們之間傳遞一個指針。 例如,主程序可以傳遞一個指向它加載的動態鏈接庫的指針。


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM