В коде C++, который я читаю, найдено следующее. Может ли кто-нибудь помочь мне понять, что делают следующие утверждения?Что означает * (int *) (буфер)?
char buffer[4096];
// some code
int size = *(int*)(buffer);
В коде C++, который я читаю, найдено следующее. Может ли кто-нибудь помочь мне понять, что делают следующие утверждения?Что означает * (int *) (буфер)?
char buffer[4096];
// some code
int size = *(int*)(buffer);
TL; DR: этот код является плохим, забыть об этом и двигаться дальше.
(buffer)
Это скобка означает, что программист был небезопасным своих собственных возможностей программирования.
С buffer
представляет собой массив символов, используя идентификатор buffer
сам по себе дает вам указатель на первый элемент: a char
Указатель.
(int*)
Это литье, преобразование указателя char
в указатель int
.
*
принимает содержимое этого целочисленного указателя, и результат сохраняется в целочисленном size
.
Обратите внимание, что этот код является полностью опасным. Многие преобразования указателей вызывают плохое поведение. Могут быть проблемы с выравниванием. Могут быть проблемы с псевдонимом указателей (правило строгого сглаживания Google). Этот конкретный код также зависит от последовательности, что означает, что он требует, чтобы содержимое массива символов имело заданный порядок байтов.
В целом, не имеет смысла использовать подписанные типы, такие как int
или char
(возможно, подписанный) при выполнении подобных действий. В частности, тип char
очень проблематичен, так как он имеет определенную приложением подпись и его следует избегать. Используйте вместо этого unsigned char
или uint8_t
.
Чуть менее плохой код будет выглядеть примерно так:
#include <stdint.h>
uint8_t buffer[4096];
// some code
uint32_t size = *(uint32_t*)buffer;
Я думаю, что ваш примерный код не должен использовать трюк разворота указателя. Использование 'memcpy' будет по-прежнему иметь возможную проблему, но, по крайней мере, UB не будет. – user694733
Как код, который по-прежнему имеет такое же неопределенное поведение, менее плохое? – 2501
@ 2501 Потому что у него нет упомянутых проблем типа. Демонстрация того, как исправить это, является целью фрагмента кода. Чтобы исправить неопределенное поведение, вам нужно сделать что-то гораздо более радикальное. – Lundin
Он принимает адрес buffer[0]
, бросает его в int*
, разыменовывает что и использует разыменованное значение для инициализации size
. Другими словами, он принимает первые sizeof(int)
байтов buffer
, делает вид, что эти байты являются int
и сохраняет это значение int в size
.
Это не * непосредственно * берет адрес 'buffer [0]'. Вместо этого массив * распадается * на указатель на его первый элемент. –
Я не могу дать upvote, пока ответ ответ также не объясняет, почему этот код сломан и его не следует использовать. – user694733
char buffer[4096];//this is an array of 4096 characters
// some code
int size = *(int*)(buffer);
будет бросить (гнилой) указатель на символ, который buffer
, к целому указателю. Затем он разыгрывает его, чтобы получить целочисленное значение . Целочисленное значение, которое вы получите от этого, будет состоять из первых четырехзначных значений массива buffer
, предполагая, что размер int
составляет 4 байта на вашем компьютере или в целом будет состоять из sizeof(int)
символов.
Другими словами, представление памяти первых символов sizeof(int)
массива buffer
будет обрабатываться так, как если бы они представляли одно целочисленное значение, так как теперь на него указывает целочисленный указатель и который будет сохранен в size
целочисленная переменная, если этот целочисленный указатель разыменован.
Это, как уже неоднократно указывалось в разделе комментариев, этот код небезопасен. Одна вещь, которая приходит на ум, заключается в том, что некоторые процессоры имеют строгие требования к выравниванию (см. this answer), и в этом случае нет гарантии, что адрес первого элемента массива buffer
соответствует требованию выравнивания целого числа, что приводит к неопределенному в этих CPU.
См. @Lundin ответ для еще большей причины, почему этот код является небезопасным и может не дать вам результат, который вы искали.
@ user694733, правда, он может быть поврежден на некоторых архитектурах из-за плохого выравнивания памяти для указателя на 'int' –
@ user694733 Спасибо за ваши отзывы, я попытался упомянуть одну из причин, по которой я знаю, приведет к неопределенной работе на некоторые процессоры. Ответ Лундина более подробно рассказывает о проблемах с этим кодом, и я чувствую, что я буду вторить тому, что уже сказано. –
Может ли кто-нибудь помочь мне понять, что делают следующие утверждения?
Первое утверждение:
char buffer[4096];
объявляет массив chars
размером 4096
.
Второе утверждение:
int size = *(int*)(buffer);
1. Первого берет прогнившего указателя на символ в массив buffer
(также под названием buffer
), который представляет собой указатель, указывающий на первый элемент, установленный на момент его заявление
2. Затем бросает ее указатель на int
или int*
3. Наконец, присваивается содержимое этого указателя (который будет иметь тип int
) переменной size
.
«сначала берет адрес массива' buffer' »неправильно, получив адрес' buffer' будет '& buffer'. Вместо этого 'buffer' * распадается на указатель * на его первый элемент. –
@JoachimPileborg спасибо, отредактировал мое сообщение! – Marievi
Я не могу дать upvote, пока ответ ответ также не объясняет, почему этот код сломан и его не следует использовать. – user694733
Вы знаете, что '(интермедиат *) buffer' средства? Если не читать о * casting *. Знаете ли вы, что делает унарный оператор разметки '*' (например, что происходит, если у вас есть '* some_pointer')? Если не прочитать об этом тоже. Затем просто объедините знания о каждом предмете, как будто они объединены в выражении, о котором вам интересно. –
Это утверждение также может вызвать исключение выравнивания на некоторых архитектурах. – dbrank0
Это утверждение также вызывает неопределенное поведение. – 2501