2016-05-11 2 views
6

В коде C++, который я читаю, найдено следующее. Может ли кто-нибудь помочь мне понять, что делают следующие утверждения?Что означает * (int *) (буфер)?

char buffer[4096]; 
// some code 
int size = *(int*)(buffer); 
+8

Вы знаете, что '(интермедиат *) buffer' средства? Если не читать о * casting *. Знаете ли вы, что делает унарный оператор разметки '*' (например, что происходит, если у вас есть '* some_pointer')? Если не прочитать об этом тоже. Затем просто объедините знания о каждом предмете, как будто они объединены в выражении, о котором вам интересно. –

+2

Это утверждение также может вызвать исключение выравнивания на некоторых архитектурах. – dbrank0

+5

Это утверждение также вызывает неопределенное поведение. – 2501

ответ

6

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; 
+5

Я думаю, что ваш примерный код не должен использовать трюк разворота указателя. Использование 'memcpy' будет по-прежнему иметь возможную проблему, но, по крайней мере, UB не будет. – user694733

+0

Как код, который по-прежнему имеет такое же неопределенное поведение, менее плохое? – 2501

+0

@ 2501 Потому что у него нет упомянутых проблем типа. Демонстрация того, как исправить это, является целью фрагмента кода. Чтобы исправить неопределенное поведение, вам нужно сделать что-то гораздо более радикальное. – Lundin

1

Он принимает адрес buffer[0], бросает его в int*, разыменовывает что и использует разыменованное значение для инициализации size. Другими словами, он принимает первые sizeof(int) байтов buffer, делает вид, что эти байты являются int и сохраняет это значение int в size.

+2

Это не * непосредственно * берет адрес 'buffer [0]'. Вместо этого массив * распадается * на указатель на его первый элемент. –

+1

Я не могу дать upvote, пока ответ ответ также не объясняет, почему этот код сломан и его не следует использовать. – user694733

14
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 ответ для еще большей причины, почему этот код является небезопасным и может не дать вам результат, который вы искали.

+0

@ user694733, правда, он может быть поврежден на некоторых архитектурах из-за плохого выравнивания памяти для указателя на 'int' –

+0

@ user694733 Спасибо за ваши отзывы, я попытался упомянуть одну из причин, по которой я знаю, приведет к неопределенной работе на некоторые процессоры. Ответ Лундина более подробно рассказывает о проблемах с этим кодом, и я чувствую, что я буду вторить тому, что уже сказано. –

3

Может ли кто-нибудь помочь мне понять, что делают следующие утверждения?

Первое утверждение:

char buffer[4096]; 

объявляет массив chars размером 4096.

Второе утверждение:

int size = *(int*)(buffer); 

1. Первого берет прогнившего указателя на символ в массив buffer (также под названием buffer), который представляет собой указатель, указывающий на первый элемент, установленный на момент его заявление

2. Затем бросает ее указатель на int или int*

3. Наконец, присваивается содержимое этого указателя (который будет иметь тип int) переменной size.

+0

«сначала берет адрес массива' buffer' »неправильно, получив адрес' buffer' будет '& buffer'. Вместо этого 'buffer' * распадается на указатель * на его первый элемент. –

+0

@JoachimPileborg спасибо, отредактировал мое сообщение! – Marievi

+1

Я не могу дать upvote, пока ответ ответ также не объясняет, почему этот код сломан и его не следует использовать. – user694733

Смежные вопросы