2

我真的对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 吗?我所做的只是侥幸吗?

4

4 回答 4

3

uint32_t是一种类型。这意味着无符号的 32 位整数。在您的系统上,它可能是unsigned int.

指向这个特定类型的指针没有什么特别之处。你可以有任何类型的指针。

C 和 C++ 中的[]实际上是指针索引表示法p[0]表示在指针指向的位置检索值。p[1]之后获取下一个内存位置的值。然后p[2]是之后的下一个位置,依此类推。

您也可以将此表示法与数组一起使用,因为当这样使用时,数组的名称将转换为指向其第一个元素的指针。

因此,您的代码plain_text[1]会尝试读取temp. 由于temp实际上不是数组,因此这会导致未定义的行为。在您的特定情况下,这种未定义行为的表现是它在没有崩溃的情况下设法读取内存地址temp,并且该地址与key存储的地址相同。

于 2015-06-17T06:02:07.717 回答
1

正式地,您的程序具有未定义的行为。

该表达式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
于 2015-06-17T05:59:48.860 回答
0

在 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]您只需了解指针算术

于 2015-06-17T06:08:33.880 回答
-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

这种情况可以解释这种行为。

于 2015-06-17T05:56:44.053 回答