C ++指针算术怪异

时间:2011-07-27 16:01:46

标签: c++ pointer-arithmetic

我发现了我的错误(几个小时后)并在以下程序中将其隔离。问题在于使用指向结构的指针时计算pst2变量值的方式。当使用指向char的指针时,一切正常。这是为什么?(使用gcc / g ++版本:( Debian 4.4.5-8)4.4.5)
(对于那些想知道的人:我正在访问包含数据分组的文件缓冲区在常规抵消。)

#include <iostream>
#include "testpa.h"

#pragma pack(push)
#pragma pack(1)
//---------------------------
struct st_one
{
    int i;
    char c;
};
//---------------------------
struct st_two
{
    long l;
    int i;
};
#pragma pack(pop)

//===========================
int main()
{
    int n=1024, np1=sizeof(st_one); //, np2=sizeof(st_two);
    st_one *pst1, *pst1a;
    st_two *pst2, *pst2a;
    char *pc1, *pc2, *pc1a, *pc2a, *pb;

    pb = new char[n];

    pst1 = (st_one*)(pb);
    pst2 = (st_two*)(pst1 + np1); //using pst1
    pc1 = (char*)(pb);
    pc2 = (char*)(pc1 + np1); //using pc1

    pst1a = (st_one*)(pb);
    pst2a = (st_two*)(pb + np1); //using pb
    pc1a = (char*)(pb);
    pc2a = (char*)(pb + np1); //using pb

    std::cout << "\npb = " << (long)pb;
    std::cout << "\n-----";
    std::cout << "\npst1 = " << (long)pst1 << "\tpst2 = " << (long)pst2;
    std::cout << "\npc1  = " << (long)pc1 << "\tpc2  = " << (long)pc2;
    std::cout << "\n-----";
    std::cout << "\npst1a = " << (long)pst1a << "\tpst2a = " << (long)pst2a;
    std::cout << "\npc1a  = " << (long)pc1a << "\tpc2a  = " << (long)pc2a;
    std::cout << "\n-----\n";

    return 0;
}

输出:

pb = 19546128

pst1 = 19546128         pst2 = 19546153  <--- WRONG!
pc1  = 19546128         pc2  = 19546133

pst1a = 19546128        pst2a = 19546133
pc1a  = 19546128        pc2a  = 19546133

5 个答案:

答案 0 :(得分:8)

这对我来说很好看。这一行:

 (pst1 + np1)

np1 st_one个实例添加到pst1所指的位置,这意味着pst1的值增加np1 * sizeof (st_one)个字节,即25( sizeof = 5),它对应于您输出的值。而不是上述,我想你想要:

 (pst1 + 1)

pc1值有效,因为它是char指针,所以行:

(pc1 + np1)

np1 * sizeof (char)个字节添加到pc1,这是5个字节。

递增指针使指针指向内存中的下一个元素,而不是下一个字节。

答案 1 :(得分:3)

您不应添加sizeof(x),因为这是自动完成的。当您递增指针(如++ p)时,地址会增加对象的大小,以便指向下一个。

向指针添加1与++ p相同。添加sizeof(x)会对增量进行两次缩放。

您的计算适用于char,因为sizeof(char)为1。

答案 2 :(得分:2)

C ++会自动将您添加的整数乘以指针所指向的元素的大小。它假设您希望通过整个元素而不是字节来推进指针。

答案 3 :(得分:2)

C和C ++中的指针运算是指针指向类型sizeof的完成时间。也就是说,int *abc = /* ... */; int *def = abc + 1会导致defint之前的结果为abc,而不是char

至于你将指针转换成long s,这是实现定义的行为,所以你可能会在不同的机器上得到奇怪的结果。

(就此而言,您在指针类型之间的转换也是如此.C ++也说明了实现的定义)

答案 4 :(得分:1)

看起来你的一切都错了。例如,对于从pst1获取pst2,您必须将其递增1,因为指针pst1的类型为st_one *,因此您必须这样写:

pst2 = (st_two*)(pst1 + 1);

..但你有:

pst2 = (st_two*)(pst1 + np1);

...其中np1是sizeof的{​​{1}},因此它将跳过尽可能多的st_one结构,因为该结构具有字节...

阅读有关指针算术的一些文档,例如this one