как работает указатель uint32_t?

Я действительно смущен тем, как работают указатели uint32_t в C ++

Я просто возился с попытками изучить TEA, и я не понял, когда они передали параметр uint32_t в функцию шифрования, затем в функции объявили переменную 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;
}

и это поразило меня, когда на выходе было значение «ключ». Я понятия не имею, как это работает … и затем, когда я попытался с plain_text [0], он вернулся со значением «temp».

Так что я чертовски застрял, пытаясь понять, что происходит.

РЕДАКТИРОВАТЬ: оглядываясь на код TEA, uint32_t * v указывает на массив, а не один беззнаковый int? и что я сделал, был просто счастливой случайностью?

2

Решение

uint32_t это тип. Это означает 32-разрядное целое число без знака. В вашей системе это, вероятно, имя typedef для unsigned int,

Нет ничего особенного в указателе на этот конкретный тип; Вы можете иметь указатели на любой тип.

[] в C и C ++ на самом деле указатель индексации. p[0] означает получить значение в том месте, на которое указывает указатель. p[1] получает значение в следующей ячейке памяти после этого. затем p[2] следующая точка после этого и так далее.

Вы также можете использовать эту запись с массивами, потому что имя массива преобразуется в указатель на его первый элемент при использовании таким образом.

Итак, ваш код plain_text[1] пытается прочитать следующий элемент после temp, поскольку temp на самом деле не массив, это вызывает неопределенное поведение. В вашем конкретном случае проявлением этого неопределенного поведения является то, что ему удалось прочитать адрес памяти после temp без сбоев, и этот адрес был тот же адрес, где key хранится.

3

Другие решения

Формально ваша программа имеет неопределенное поведение.

Выражение 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
1

В 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] ты просто должен понять арифметика указателей.

0

uint32_t * plain_text; // в памяти зарезервировано 4 байта простой текст

uint32_t key; // в памяти следующие 4 байта после простой текст зарезервированы для ключ

таким образом: &plain_text [0] представляет собой plain_text и &plain_text [1] относится к

следующие 4 байта, которые находятся в &ключ

Этот сценарий может объяснить такое поведение.

-1
По вопросам рекламы [email protected]