[英]How are memory addresses assigned in C?
我了解到數組的值是根據內存地址“並排”存儲的,因此數組的名稱是指向數組第一個值的指針:
#include <stdio.h>
int main() {
int array[] = {1, 2, 3};
printf("%d", *array); // The first value of array: 1
printf("%d", *(array + 1)); // The second value of array: 2
}
直覺上,我認為代碼中一個接一個聲明的變量只是簡單地分配了相鄰的內存地址。 這個想法與在內存中定義數組的方式背道而馳,因為我的代碼中的所有變量都將組成一個大數組。
我的問題是,基本上,有沒有辦法知道一個變量的地址是什么,相對於我的程序中定義的其他變量,而不是打印它的地址?
直覺上,我認為代碼中一個接一個聲明的變量只是簡單地分配了相鄰的內存地址。
C 編譯器將您的代碼(專為“C 抽象機”設計)轉換為任何會以完全不同的語言創建相同行為的代碼(例如,目標 CPU 的機器代碼)。
作為這種“轉換為完全不同的東西”的一部分,局部變量通常不復存在(由沒有內存地址的寄存器代替,因為寄存器不是內存),即使它們確實存在,它們也可以按任何順序排列,或者重疊(例如,用於在不同時間使用的 2 個不同局部變量的相同內存)。
數組“更特殊”,因為它們通常更大,編譯器更難優化(同時遵守定義抽象機器行為的語言規則); 所以數組元素在內存中保持連續的可能性更大; 但這不是任何形式的保證。
例如,請考慮以下代碼:
int foo(int bar) {
int myArray[] = { 1, 2, 3, 4};
if(bar < 0) return bar + myArray[0];
if(bar > 0) return bar + myArray[2];
return bar + myArray[1];
}
如果您編譯它(就像我在https://godbolt.org/ 上使用 Godbolt 所做的那樣)並檢查輸出,您可能會看到如下內容:
foo(int):
test edi, edi
js .L6
lea eax, [rdi+3]
mov edx, 2
cmove eax, edx
ret
.L6:
lea eax, [rdi+1]
ret
如你看到的; 該數組根本不再存在(並且所有數組元素都沒有內存地址),因為在這種情況下,編譯器足夠聰明以進行優化。
您的代碼也會發生同樣的事情(數組不再存在並且根本沒有地址)。 變成這樣:
.LC0:
.string "%d"
main:
sub rsp, 8
mov esi, 1 // The value "1" originally came from the array
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
mov esi, 2 // The value "2" originally came from the array
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
我的問題是,本質上,有沒有辦法知道變量的地址是什么。
本質上; 不。 這就像給馬喂胡蘿卜,然后試圖確定馬大便后原始胡蘿卜的分子最終會在哪里。
您唯一能做的就是在運行時獲取地址(例如使用&variable
),這(當且僅當編譯器無法證明獲取地址的代碼可以被丟棄/忽略時)具有副作用強制編譯器確保變量確實有地址。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.