简体   繁体   中英

Casting long int as a struct pointer

I know this is a rather noobish question, but no amount of googling or permutations of code seem to work.

I have a structure which is defined like this.

typedef struct
{
    int rate;
    int duration;
} DummyStructure;

Now, i try to use code similar to this.

//
DummyStructure* structure;
DummyStructure* structure2;
long int point;

//
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int)&structure;

// now i'd like to set structure2 to the same memory location as 1.
// point is the 8-byte int location (i assume?) of structure.
// so naturally i'd assume that by casting as a DummyStructure pointer
// that long int would act as a pointer to that 1.

// It doesn't.
structure2 = (DummyStructure*)point;

I stress that i've tried every permutation of ** and * that is possible. I just don't get it. Either it doesn't compile, or it does, and when it does i end up with seemingly random numbers for the fields contained in structure2. I assume that somehow i'm winding up with an incorrect memory location, but how else can you get it except from using the &?

I have the memory location, right? How do i set the structure to that location?

EDIT; I forgot to mention (and subsequent answers have asked) but i'm intending to use this to wrap libvorbis for jni. Using jni means that i can't pass-back any of the structs that libvorbis does, but it requires them for its core functions. Therefore my wrapper is going to use vorbis directly to make the structs, and i pass back to java the pointer to them so that when i need to fill the buffer with more sound, i can simply re-reference the struct objects from the integer value of the pointer.

Why are you trying to cast pointers to integers and back? Is it just to learn, to figure something out, to work around some (untold) restriction, or what? It's a rather strange thing to be doing in a "plain" program such as this, as there is no point.

One likely cause of your problems is that there's no guarantee that a pointer will even fit in a long int . You can check by adding this code:

printf("a regular pointer is %u bytes, long int is %u",
  (unsigned int) sizeof structure, (unsigned int) sizeof point);

If the numbers printed are different, that's probably the largest cause of your problems.

If you're using C99, you should #include <stdint.h> and then use the intptr_t type instead of unsigned long to hold a pointer, in any case.

structure is already a pointer, so you don't have to take the address there:

long int point = reinterpret_cast<long int>(structure);
DummyStructure* structure2 = reinterpret_cast<DummyStructure*>(point);

structure is already a pointer. You just want to do point = (long int) structure; (although, realistically, why a long int is involved at all, I don't know. It's a lot easier to just do structure2=structure; which works fine since structure and structure2 are both pointers.)

When you do &structure you're getting the memory location where the pointer itself is stored, which is why it isn't the correct value. You really probably don't want to ever use &structure unless it's being passed into a function which is going to change which DummyStructure structure points to.

Others have answered your question, but I'd like to make a more general comment. You mention JNI; in this case, you don't want long int , but jlong (which will be a typedef to either long int or long long int , depending on the machine. The problem is that long will have a different size, depending on the machine, and will map to a different Java type. Of course, you're counting on the fact that jlong will be big enough to hold a pointer, but since jlong is 64 bits, this seems like a safe bet for the immediate future (and beyond—I don't see a time coming where 64 bits of addressing doesn't suffice).

Also, I would suggest you borrow an idea from Swig, and avoid the subtleties of pointer to integral conversions, by using something like the following:

jlong forJNI = 0;
*reinterpret_cast<DummyStructure*>( &forJNI ) = structure;
//  ...
structure2 = *reinterpret_cast<DummyStructure*>( &forJNI );

This is ugly, but it is guaranteed to work (with one caveat) for all systems where sizeof(DummyStructure*) <= 64 .

Just be sure to compile with strict aliasing turned off. (You have to do this anytime you cast between pointers and ints. IMHO, you shouldn't have to in cases where the casts are visible to the compiler, but some compiler writers prefer breaking code intentionally, even when the intent is clear.)

Long ints aren't the same as pointers. Why don't you just do:

DummyStructure** point;

structure = malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = &structure;

structure2 = *point;

The problem is probably a combination of the fact that 1) you don't dereference point. structure2 is a pointer to structure which is itself a pointer. You'd have to do:

structure2 = *((DummyStructure*)point);

But on top of that is the fact that long ints aren't the same as pointers. There's probably also a signedness issue here.

point = (long int)&structure;

This takes the address of structure which is a DummyStructure* and assign it to point . So point should be a double pointer (pointer to pointer). And when you assign structure2 , it should be properly type casted.

typedef struct
{
    int rate;
    int duration;
} DummyStructure;

DummyStructure* structure;
DummyStructure* structure2;
long int **point;
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int **)&structure;
structure2 = (DummyStructure*)*point;

If your intention is to make structure2 point to the same memory location as structure , why don't you directly assign it rather than having an intermediate long int ** .

The bug is that point is the address of structure , which is itself a pointer to a DummyStructure . In order for structure2 to point to the same thing as structure , you need to dereference point . Ignoring for a second all length, signedness, and similar issues,

structure2 = *(DummyStructure**)point;

would fix your code. But why not just:

structure2 = structure;

If you really want to hold a pointer in something generic, hold it in a void* . At least that's the right size.

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