简体   繁体   中英

C++ Pointer Math

Got a question about C++ Pointer addition. If you look at the screen shot provided you can basically see I'm doing a memcpy(m_pBuf + m_iWritePtr .... and this memory pointer addition is not working as expected.

I had thought that the addition of m_pBuf + m_iWritePtr would add m_iWritePtr bytes to my memory address m_pBuf. m_pBuf is a pointer to a structure array; ie (T *)m_pBuf = new T[cnt] where T is a typename and cnt is the number of T objects allocated. T is, in this case a simple structure. The sizeof(T) in this case is 260.

The memcpy call is throwing a fault and I know my pointer math is wrong but I'm not 100% sure why. The memcpy is coded to, I thought, to take the base address and add some n * 260 bytes to get an offset into the buffer. NOTE: This code use to work when this was not a template implementation and T was simply a char *. Now that T is a template of some typename, the offset addition no longer works as expected.

So if you look at the screen shot below, here are the results of various calculations/references I did using the compiler's debugger/inspector and a calculator:

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)

I'm trying to understand what's going on here. The first two seem correct but I don't understand why none of these are equal. This is 32bit compiler on Windows 7-64bit.

在此处输入图片说明

To further explain, this is a ring buffer of type T with a size of n * T objects of storage. Here is the code:

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;
}

Pointer math works in a logical manner. When you add n to a pointer of type Foo it advances the pointer sizeof(Foo) * n bytes, not n bytes. Anyway, why would you add the one pointer to another anyway? What are you trying to accomplish by doing this?

Be careful about the order of the operations. I am guessing you did the ++ first:

m_pBuf++     = 0x01E8EBFC

The effect of the postincrement is to change the value but print out the old value , so if you printed m_pBuf i am guessing you would get 0x1E8ED00.

If you then ran

m_pBuf+1     = 0x01E8EE04

the new value is correct (the difference is sizeof(T) = 260)

Show the neighboring code, and be sure that you are careful regarding statements with side effects.

As Ed and Martin said, pointer math involves the size of the type for the pointer.

Adding one to a pointer increases the address of the pointer by the size of the type.

Now one thing you don't mention is the type of m_pBuf .

But from your debugging session, the compiler/debugger believes that `(char *)&m_pBuf[1] - (char *)m_pBuf == 0x01E8EE04 - 0x01E7E0E0 == 0x10D24 == 68900 decimal

68900 / 260 (sizeof T) == 265

So the compiler/debugger believes that m_pBuf is T[265].

But as Foo Bah noted, the m_pBuf++ modified the pointer. So the two debugger view expressions m_pBuf[[1]] and m_pBuf+1 probably occurred after m_pBuf++ since the window for m_pBuff++ shows a smaller value than the other two test expressions.

Readjusting for that scenario, we end up with m_pBuf is T[263].

If you wanted to access the first T bytes from the beginning of m_pBuf, you can cast m_pBuf to (char *) before doing the pointer arithmetic. There are most likely more elegant solutions, but you haven't shown enough code yet - those darn debugger expression windows are covering up important stuff!

It might help to post the code.

Remember incrementing a pointer of type T increases it by sizeof(T) bytes.

Let me guess: m_pBuf isn't a pointer to T* but a pointer to T[265] , right? That's the only way that m_pBuf+1 could equal the address of (char*)m_pBuf + 260*265 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM