【问题标题】:C++ Pointer MathC++ 指针数学
【发布时间】:2011-02-12 03:51:18
【问题描述】:

有一个关于 C++ 指针添加的问题。如果您查看提供的屏幕截图,您基本上可以看到我正在执行 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 是一个简单的结构。本例中 sizeof(T) 为 260。

memcpy 调用出错,我知道我的指针数学错误,但我不是 100% 确定原因。我认为 memcpy 被编码为获取基地址并添加一些 n * 260 字节以获得缓冲区的偏移量。注意:当这不是模板实现并且 T 只是一个 char * 时,此代码可以正常工作。现在 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)

我试图了解这里发生了什么。前两个似乎是正确的,但我不明白为什么这些都不相等。这是 Windows 7-64 位上的 32 位编译器。

为了进一步解释,这是一个 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;
}

【问题讨论】:

    标签: c++ math pointers


    【解决方案1】:

    注意操作的顺序。我猜你是先做 ++ 的:

    m_pBuf++     = 0x01E8EBFC
    

    后增量的效果是更改值但打印出旧值,所以如果您打印 m_pBuf,我猜您会得到 0x1E8ED00。

    如果你然后跑了

    m_pBuf+1     = 0x01E8EE04
    

    新的值是正确的(差是sizeof(T) = 260)

    显示相邻的代码,并确保您注意带有副作用的语句。

    【讨论】:

    • 不,m_pBuf++ 不在代码中。它被放入我的 IDE 调试器中以评估“m_pBuf++”和“m_pBuf+1”的结果。代码方面的情况是,这是一个大小为 N 的 T 个对象的环形缓冲区。我用一个线程将数据放入环形缓冲区,然后在另一个线程中取出。上面的代码是我试图将数据放入缓冲区的部分。我做了一些工作来查看我在缓冲区 (m_iWritePtr) 中的位置,然后使用 memcpy 将对象存储在适当的 m_iWritePtr 偏移处。
    • 0x01E8EE04 - 0x01E7E0E0 不等于 260。我得到 68,900。
    • 0x01E8EBFC-0x01E8EE04 等于 260。m_iWritePtr 是实际的写指针吗?如果是这样,你为什么不直接在那个地址做 memcpy 呢? (您可能想要添加偏移量,而不是地址
    • " 我猜你会得到 0x1E8ED00" 我认为事实并非如此。在左侧的屏幕截图中,调试器显示地址是 0x01E7E0E0 还是 0x01E7E0E0 是我的变量的内存地址?我想如果你是对的,那么我的错误是我误解了我的调试器向我展示的内容。这是 C++ Builder Rad XE
    • 语句 x++,当 x 是 T* 类型时,返回 x,但将 x 的地址移动 sizeof(T) 个字节。从静态屏幕截图中不清楚哪个语句首先被评估。我也不完全确定您的 IDE / 调试器实际评估结果的顺序。是否有即时窗口 [类似于 VS 即时窗口] 或控制台 [如 GDB]?
    【解决方案2】:

    指针数学以合乎逻辑的方式工作。当您将 n 添加到 Foo 类型的指针时,它会推进指针 sizeof(Foo) * n 字节,而不是 n 字节。无论如何,你为什么要将一个指针添加到另一个指针?您这样做是为了达到什么目的?

    【讨论】:

    • 这是我的理解,但数字没有加起来。 m_pBuf+1 = 0x01E8EE04 不等于 0x01E7E1E4(计算器结果显示结果为 0x01E7E0E0 + 260)
    【解决方案3】:

    正如 Ed 和 Martin 所说,指针数学涉及指针类型的大小。

    给指针加一会使指针的地址增加类型的大小。

    现在你没有提到的一件事是m_pBuf 的类型。

    但是从您的调试会话中,编译器/调试器认为 `(char *)&m_pBuf[1] - (char *)m_pBuf == 0x01E8EE04 - 0x01E7E0E0 == 0x10D24 == 68900 十进制

    68900 / 260(T 大小)== 265

    所以编译器/调试器认为 m_pBuf 是 T[265]。

    但正如 Foo Bah 所说,m_pBuf++ 修改了指针。因此m_pBuf[[1]]m_pBuf+1 这两个调试器视图表达式可能出现在m_pBuf++ 之后,因为m_pBuff++ 的窗口显示的值小于其他两个测试表达式。

    针对这种情况重新调整,我们最终得到 m_pBuf is T[263]。

    如果要访问 m_pBuf 开头的前 T 个字节,可以在进行指针运算之前将 m_pBuf 转换为 (char *)。很可能有更优雅的解决方案,但您还没有显示足够的代码 - 那些该死的调试器表达式窗口正在掩盖重要的东西!

    【讨论】:

      【解决方案4】:

      发布代码可能会有所帮助。

      记住增加一个类型为 T 的指针会增加 sizeof(T) 个字节。

      【讨论】:

        【解决方案5】:

        让我猜猜:m_pBuf 不是指向T* 的指针,而是指向T[265] 的指针,对吧?这是m_pBuf+1 可以等于(char*)m_pBuf + 260*265 地址的唯一方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-04
          • 1970-01-01
          • 2013-06-18
          • 1970-01-01
          • 2016-01-15
          相关资源
          最近更新 更多