2015-04-30 15 views
0

я наткнулся на строку кода, написанного на C++:Является ли этот тип литой или какой-либо арифметикой указателя?

long *lbuf = (long*)spiReadBuffer; 

И получается, что «spiReadBuffer» массив байтов с 12 элементами. Но я немного смущен. Я думаю, что я знаком с определением указателей, и я вижу, что «lbuf» - это тип «длинный» указатель. Кроме того, я думал, что для литья мы можем сделать что-то вроде этого:

y = (int) x;  

Но что, если я положил «*» после «ИНТ» так же, как мой первый пример, где есть один после «долго»? Я извиняюсь, если это действительно тривиальный вопрос, но когда я проходил темы литья и указателей, я не сталкивался со своим делом, и я действительно не понимал этого. Буду признателен, если вы можете направить меня или познакомить меня с любыми соответствующими материалами или ресурсами.

+0

Да, это тип. Что такое 'y'? Я полагаю, что это 'int'. –

+0

Как объявляется 'y'? Предположим, что это был 'long * y' - what * type *, если он * указывает на *? – usr2564301

+1

С этим типом литья можно получить доступ к 'uint8_t spiReadBuffer [12];' как если бы это был 'uint32_t buffer [3];', то есть 32 бита за раз. На данный момент у него нет арифметики. –

ответ

1

Это называется тип punning. Он комментирует компилятор, считывая память, занимаемую объектом, как если бы она была другого типа.

В вашем случае массив spiReadBuffer распадается на указатель на его первый элемент, тогда указатель будет отлит и сохранен. Когда вы разыщите этот указатель, вы получите доступ к началу массива, как если бы он был long.

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

Существует два способа (что я знаю), чтобы безопасно набирать слова. Первый соответствует стандарту: std::memcpy.

char spiReadBuffer[12]; 
long rbAsLong; 
std::memcpy(&rbAsLong, &spiReadBuffer, sizeof rbAsLong); 
// rbAsLong contains the first four bytes of spiReadBuffer, reinterpreted as a long. 

Второй включает в себя расширение, которое часто предоставляется составителей (но вы должны проверить), что расширяет поведение профсоюзов.

union { 
    char buf[12]; 
    long asLong; 
} spiReadBuffer; 

Стандарт утверждает, что запись в член союза, а затем чтение из другого члена, является неопределенным поведением. Эти расширения компилятора позволяют определить его как безопасную реинтерпретацию.

0

в массивах C/C++ обрабатывают таким же образом компилятором:

char spiReadBuffer[12]; 
char* pBuffer; 

компилятор будет рассматривать как spiReadBuffer и пиксельный буфер в качестве указателей.

Код фрагмент

long *lbuf = (long*)spiReadBuffer; 

является примером литья типа, только это для типов указателей. Символ * преобразуется в длинный *; Вы можете сказать, что это тип арифметики указателя, потому что теперь вы можете читать sizeof (long) байты от spiReadBuffer, используя long * (вместо одного байта за раз).

Второй фрагмент, который вы показали: y = (int) x; также является отличным, но не для указателей;

+0

Вы имели в виду для написания 'char * pBuffer;'? – user463035818

+0

@ tobi303 yes Я сделал, спасибо! – Pandrei

+3

* компилятор будет обрабатывать как spiReadBuffer, так и pBuffer как указатели. * - Нет. Массивы не являются указателями, а указатели не являются массивами. – Quentin

0

Рассмотрим этот фрагмент:

char spiReadBuffer[] = {1,2,3,4,5,6,7,8}; 
long *lbuf = (long*)spiReadBuffer; 
printf ("%08x\n", lbuf[0]); 

Он будет печатать 04030201 на маленькой архитектуры Endian или 01020304 на маленькой архитектуры Endian.

После long *lbuf = (long*)spiReadBufferlBuf заявление указывает на начало spiReadBuffer и lbuf[0] (или *lBuf) позволяет прочитать первые 4 байта spiReadBuffer как долго.

+0

Ничего себе !! Очень тщательные ответы Квентина, Чакера Маллека, Пандрея и Майкла Уолза. Поэтому, чтобы убедиться, что я понял это правильно, «(длинный *)» сегмент кода передает первые четыре байта «spiReadBuffer» в «длинную» переменную, которая имеет четыре байта. Эти четыре байта указывают на покупку четырехбайтового указателя с именем «lbuf». –

+1

@Jamycodes Кредит, которому должен быть предоставлен кредит: ответ Chaker Malleks, на который вы ссылаетесь (который, кажется, удален по уважительным причинам), был на самом деле Prateek Joshi и может быть найден здесь [http://prateekvjoshi.com/2014/08/02/what-is-pointer-casting /) – user463035818

+1

@Jamycodes: «(длинный *)» сегмент кода передает первые четыре байта «spiReadBuffer» в «длинную» переменную, которая имеет четыре байта: не вполне. '(long *) отличает' spiReadBuffer', который имеет тип 'char *' (указатель на char) на 'long *' (указатель на long). –

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