繁体   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