簡體   English   中英

uint32_t 指針在這段代碼中是如何工作的?

[英]How does an uint32_t pointer work in this code?

我真的對uint32_t指針在 C++ 中的工作方式感到困惑

我只是在擺弄試圖學習TEA ,我不明白他們何時將uint32_t參數傳遞給 encrypt 函數,然后在函數中聲明了一個uint32_t變量並將參數分配給它,就好像參數是一個數組一樣。

像這樣:

void encrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, i;

所以我決定玩轉 uint32_t 指針,並寫了這段簡短的代碼:

int main ()
{
    uint32_t *plain_text;
    uint32_t key;
    unsigned int temp = 123232;
    plain_text = &temp;
    key = 7744;

    cout << plain_text[1] << endl;

    return 0;
}

當輸出是“key”的值時,它讓我大吃一驚。 我不知道它是如何工作的……然后當我嘗試使用 plain_text[0] 時,它返回了“temp”的值。

所以我被困在地獄里,試圖了解發生了什么。

回顧一下 TEA 代碼, uint32_t* v指向一個數組而不是單個 unsigned int 嗎? 我所做的只是僥幸嗎?

uint32_t是一種類型。 它表示無符號 32 位整數。 在您的系統上,它可能是unsigned int的 typedef 名稱。

指向這個特定類型的指針沒有什么特別之處。 您可以擁有指向任何類型的指針。

C 和 C++ 中的[]實際上是指針索引符號 p[0]表示在指針指向的位置檢索值。 p[1]獲取之后下一個內存位置的值。 然后p[2]是之后的下一個位置,依此類推。

您也可以將這種表示法用於數組,因為這樣使用時,數組的名稱會轉換為指向其第一個元素的指針。

因此,您的代碼plain_text[1]嘗試讀取temp之后的下一個元素。 由於temp實際上不是一個數組,這會導致未定義的行為 在您的特定情況下,這種未定義行為的表現是它設法在temp之后讀取內存地址而不會崩潰,並且該地址與存儲key地址相同。

正式地,您的程序具有未定義的行為。

表達式plain_text[1]等價於*(plain_text + 1) ([expr.sub] / 1)。 盡管您可以指向數組末尾的某個地址(出於指針運算的目的,不是數組的對象仍被視為單元素數組 ([expr.unary.op] / 3)),但您不能取消引用此地址([expr.unary.op] / 1)。

此時的編譯器可以做任何它想,在這種情況下它只是決定把表達式就好像它指向一個數組,並且plain_text + 1 ,即&temp + 1點到下一個uint32_t堆棧中的對象,在這種情況下,巧合是key

如果您查看程序集,您可以看到發生了什么

mov DWORD PTR -16[rbp], 123232 ; unsigned int temp=123232;
lea rax, -16[rbp]
mov QWORD PTR -8[rbp], rax     ; plain_text=&temp;
mov DWORD PTR -12[rbp], 7744   ; key=7744;
mov rax, QWORD PTR -8[rbp]
add rax, 4                     ; plain_text[1], i.e. -16[rbp] + 4 == -12[rbp] == key
mov eax, DWORD PTR [rax]
mov edx, eax
mov rcx, QWORD PTR .refptr._ZSt4cout[rip]
call    _ZNSolsEj              ; std::ostream::operator<<(unsigned int)
mov rdx, QWORD PTR .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_[rip]
mov rcx, rax
call    _ZNSolsEPFRSoS_E       ; std::ostream::operator<<(std::ostream& (*)(std::ostream&))
mov eax, 0
add rsp, 48
pop rbp
ret

在 C 和 C++ 中,數組衰減為指針,導致數組/指針等效

a[1]

a是簡單類型時相當於

*(a + 1)

如果a是一個簡單類型的數組, a將盡早衰減到元素 0 的地址。

int arr[5] = { 0, 1, 2, 3, 4 };
int i = 10;

int* ptr;

ptr = arr;
std::cout << *ptr << "\n"; // outputs 0
ptr = &arr[0]; // same address
std::cout << *ptr << "\n"; // outputs 0
std::cout << ptr[4] << "\n"; // outputs 4
std::cout << *(ptr + 4) << "\n"; // outputs 4
ptr = &i;
std::cout << *ptr << "\n"; // outputs 10
std::cout << ptr[0] << "\n";
std::cout << ptr[1] << "\n"; // UNDEFINED BEHAVIOR.
std::cout << *(ptr + 1) << "\n"; // UNDEFINED BEHAVIOR.

要理解ptr[0]ptr[1]你只需要理解 指針運算

uint32_t *plain_text; // In memory, four bytes are reserved for ***plain_text***

uint32_t key; // In memory, the next four bytes after ***plain_text*** are reserved for ***key***

因此: &plain_text[0]是 plain_text 並且&plain_text[1]指的是在&key處的接下來的四個字節。

這種情況可以解釋這種行為。

暫無
暫無

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

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