I found my bug (after a few hours) and isolated it in the following program. The problem is with the way in which the pst2 variable's value is calculated when using pointers to a struct. When using pointers to char, all works fine. Why is this?
(Using gcc/g++ version: (Debian 4.4.5-8) 4.4.5)
(For those who are wondering: I'm accessing a file-buffer containing data-groupings at regular offsets.)
#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;
}
Output:
pb = 19546128
pst1 = 19546128 pst2 = 19546153 <--- WRONG!
pc1 = 19546128 pc2 = 19546133
pst1a = 19546128 pst2a = 19546133
pc1a = 19546128 pc2a = 19546133
That looks fine to me. The line:
(pst1 + np1)
adds np1
instances of st_one
to what pst1
points at, which means that pst1
s value is incremented by np1 * sizeof (st_one)
bytes, which is 25 (sizeof = 5), which corresponds to the values you've outputted. Instead of the above, I think you wanted:
(pst1 + 1)
The pc1
value works because that is a char
pointer, so the line:
(pc1 + np1)
adds np1 * sizeof (char)
bytes to pc1
, which is 5 bytes.
Incrementing a pointer makes the pointer point to the next element in memory, not the next byte.
You shouldn't add sizeof(x)
, because that is done automatically. When you increment a pointer, like ++p, the address is incremented by the size of the object, so that it points to the next one.
Adding 1 to a pointer is the same as ++p. Adding sizeof(x)
scales the increment twice.
Your calculations work fine for char, because sizeof(char) is 1.
C++ automatically multiplies the integer you're adding by the size of the element the pointer points to. It assumes you want to advance the pointer by whole elements, not bytes.
Pointer arithmetic in C and C++ is done times the sizeof
the pointed to type of the pointer. That is, int *abc = /* ... */; int *def = abc + 1
results in def
having a result an int
ahead of abc
, not a char
.
As for your casting of the pointers into long
s, that's implementation defined behavior, so you might get strange results on different machines from doing that.
(For that matter, so is your casting between pointer types. C++ says that's implementation defined too)
It looks like you got everything wrong. For example, for get pst2 from pst1, you have to increment it by one, as pointer pst1
is of type st_one *
, so you have to write like this:
pst2 = (st_two*)(pst1 + 1);
.. but you have:
pst2 = (st_two*)(pst1 + np1);
... where np1 is a sizeof
of st_one
, so it will skip as many st_one
structures as that structure has bytes...
Read some docs on pointer arithmetic, like this one.
来源:https://stackoverflow.com/questions/6847538/c-pointer-arithmetic-weirdness