C ++ Pointer Math - PullRequest
       26

C ++ Pointer Math

1 голос
/ 12 февраля 2011

Есть вопрос о добавлении C ++ Pointer. Если вы посмотрите на снимок экрана при условии, что вы в основном видите, что я делаю memcpy (m_pBuf + m_iWritePtr .... и это добавление указателя памяти не работает должным образом.

Я думал, что добавление m_pBuf + m_iWritePtr добавит байты m_iWritePtr к моему адресу памяти m_pBuf. m_pBuf - указатель на массив структур; то есть (T *) m_pBuf = new T [cnt], где T - это имя типа, а cnt - количество выделенных объектов T. В данном случае это простая структура. Размер (T) в этом случае составляет 260.

Вызов memcpy вызывает ошибку, и я знаю, что моя математика указателя неверна, но я не уверен на 100% почему. Я думал, что memcpy закодирован, чтобы взять базовый адрес и добавить несколько n * 260 байтов, чтобы получить смещение в буфере. ПРИМЕЧАНИЕ. Этот код используется для работы, когда это не было реализацией шаблона, а T был просто символом *. Теперь, когда T является шаблоном с некоторым типом имени, добавление смещения больше не работает, как ожидалось.

Итак, если вы посмотрите на снимок экрана ниже, вот результаты различных вычислений / ссылок, которые я сделал, используя отладчик / инспектор компилятора и калькулятор:

The memory address of m_pBuf     = 0x01E7E0E0

The memory address of m_pBuf[1]  = 0x01E8EE04
the memory address of m_pBuf+1     = 0x01E8EE04
the memory address of m_pBuf++     = 0x01E8EBFC  
the memory address of m_pBuf+260   = 0x01E7E1E4 (the calculator's result)

Я пытаюсь понять, что здесь происходит. Первые два кажутся правильными, но я не понимаю, почему ни один из них не равен. Это 32-битный компилятор в Windows 7-64bit.

enter image description here

Для дальнейшего объяснения, это кольцевой буфер типа T с размером n * T объектов хранения. Вот код:

template<typename T>
bool TMsgBuffer<T>::PutMsgEx(T *pBuf, unsigned long nObjCount )
{
 bool bResult = false;
 unsigned long MaxWriteSize, nPutLen;

 Lock();

 MaxWriteSize = GetMaxWriteSize();  // this returns size of my buffer in total.
 nPutLen = nObjCount * m_nObjSize;  // m_nObjSize is set else where to sizeof(T)


 if(nPutLen <= MaxWriteSize)
 {
     // easy case, no wrapping
     if( m_iWritePtr + nPutLen <= m_nBufSize )
     {
         memcpy(m_pBuf + m_iWritePtr, pBuf, nPutLen);
         m_iWritePtr += nPutLen;
     }
     else // need to wrap
     {
         m_iFirstChunkSize = m_nBufSize - m_iWritePtr;
         m_iSecondChunkSize = nPutLen - m_iFirstChunkSize;

         memcpy(m_pBuf + m_iWritePtr, pBuf, m_iFirstChunkSize );
         memcpy(m_pBuf, pBuf + m_iFirstChunkSize, m_iSecondChunkSize );

         m_iWritePtr = m_iSecondChunkSize;
     }

     //m_MsgCount++;
     m_MsgCount+= nObjCount;
     bResult = true;
 }

 Unlock();

 return bResult;
}

Ответы [ 5 ]

2 голосов
/ 12 февраля 2011

Как сказали Эд и Мартин, математика указателя включает в себя размер типа для указателя.

Добавление одного к указателю увеличивает адрес указателя на размер типа.

Теперь одна вещь, которую вы не упоминаете, это тип m_pBuf.

Но из вашего сеанса отладки компилятор / отладчик считает, что `(char *) & m_pBuf [1] - (char *) m_pBuf== 0x01E8EE04 - 0x01E7E0E0 == 0x10D24 == 68900 десятичных

68900/260 (sizeof T) == 265

Таким образом, компилятор / отладчик считает, что m_pBuf - это T [265].

Но, как заметил Фу Бах, m_pBuf++ изменил указатель.Таким образом, два выражения представления отладчика m_pBuf[[1]] и m_pBuf+1, вероятно, произошли после m_pBuf++, поскольку окно для m_pBuff++ показывает меньшее значение, чем два других тестовых выражения.

Настраивая для этого сценария, мы заканчиваемс m_pBuf - T [263].

Если вы хотите получить доступ к первым T байтов с начала m_pBuf, вы можете привести m_pBuf к (char *) перед выполнением арифметики указателя.Скорее всего, есть более элегантные решения, но вы еще не показали достаточно кода - эти проклятые окна выражений отладчика скрывают важные вещи!

2 голосов
/ 12 февраля 2011

Указатель математики работает в логической манере.Когда вы добавляете n к указателю типа Foo, он продвигает указатель sizeof(Foo) * n байтов, а не n байтов.В любом случае, зачем вам добавлять один указатель к другому?Что вы пытаетесь сделать, делая это?

2 голосов
/ 12 февраля 2011

Будьте внимательны к порядку операций. Я предполагаю, что вы сначала сделали ++:

m_pBuf++     = 0x01E8EBFC

Эффект постинкремента состоит в том, чтобы изменить значение, но распечатать старое значение , поэтому, если вы напечатаете m_pBuf, я предполагаю, что вы получите 0x1E8ED00.

Если вы тогда бежали

m_pBuf+1     = 0x01E8EE04

новое значение верное (разница есть sizeof (T) = 260)

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

1 голос
/ 12 февраля 2011

Это может помочь опубликовать код.

Помните, что увеличение указателя типа T увеличивает его на размер байтов (T).

0 голосов
/ 12 февраля 2011

Позвольте мне угадать: m_pBuf это не указатель на T*, а указатель на T[265], верно?Это единственный способ, которым m_pBuf+1 может быть равен адресу (char*)m_pBuf + 260*265.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...