将长整型转换为结构体指针

3

我知道这可能是一个初学者的问题,但是无论我如何搜索或排列代码,都似乎没有解决。

我有一个定义如下的结构。

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;

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

我强调我已经尝试了所有可能的**和*的排列组合,但是我就是搞不定。要么它无法编译,要么它可以编译,但当我使用structure2中包含的字段时,我最终得到的似乎是随机数字。我认为我以某种方式获得了不正确的内存位置,但除了使用&之外,还能怎么样才能得到呢?

我有内存位置,对吗?我该如何将结构设置为该位置?

编辑;我忘记提到(后续答案已经询问),但我的目的是使用此功能来包装jni的libvorbis。使用jni意味着我无法传回libvorbis所做的任何结构,但它需要这些结构作为其核心功能。因此,我的包装器将直接使用vorbis来创建这些结构,并将它们的指针传回给java,以便在需要用更多声音填充缓冲区时,我只需要从指针的整数值重新引用结构对象。


1
请注意,您不应该将malloc(3)的返回值强制转换--只需#include <stdlib.h>,您将获得允许编译器为您处理一切的malloc(3)原型。这些强制转换可能会隐藏编译器警告消息,这些消息会提醒您代码中的错误。 - sarnold
很可能 long 不足以容纳指针值。 使用 (u)intptr_t, size_t, 或 long long 可能会得到更好的结果。 - Alexey Frunze
出于好奇,你为什么要使用 long int 呢? - Keith Irwin
Alex,运气不应该参与其中,因为DummyStructure**可以很好地工作。 - Dan
@Dan:没错。我很少见到不使用指针作为指针的好理由。 - Alexey Frunze
3
由于这个问题标记为“jni”,我猜他想将指针转换为一个类型,以便将其作为句柄传递给Java应用程序。 - Björn Pollex
7个回答

5
为什么要将指针转换为整数再转回来?这是为了学习、弄清楚某些问题,还是为了绕过某些限制?在这样一个“简单”的程序中做这样的事情似乎很奇怪,因为这样并没有意义。
你遇到问题的一个可能原因是指针甚至可能无法适合于long int。您可以通过添加以下代码进行检查:
printf("a regular pointer is %u bytes, long int is %u",
  (unsigned int) sizeof structure, (unsigned int) sizeof point);

如果打印出来的数字不同,那可能是问题的最大原因。
如果您使用的是C99,应该包含“”并使用“intptr_t”类型而不是“unsigned long”来保存指针。无论如何,在任何情况下。

1
如果 long int 不足以容纳一个指针,将 long int 转换为指针类型的转换不应该编译。 - James Kanze

4

structure已经是一个指针,所以您不需要在那里取地址:

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

1
如果long int比指针的大小还要小,那么第二次转换就无法编译通过。(在现代计算机上不太可能出现这种情况,但我曾经在一些系统上工作过,其中指针是48位,而long int只有32位。) - James Kanze

3
structure已经是一个指针。你只需要执行point = (long int) structure;(虽然实际上,我不知道为什么要涉及long int。更容易的方法是structure2=structure;,因为structurestructure2都是指针)。当你执行&structure时,你得到的是指针本身存储的内存地址,这就是为什么它不是正确的值。除非将其传递到一个函数中,该函数将更改DummyStructure structure所指向的内容,否则你可能永远不想使用&structure

这是一个不好的想法,因为C规范并不保证长整型与指针具有相同的长度。 - Dan
当然这是个坏主意。整个问题本身就是个坏主意。没有一个整数类型能够保证与指针长度相同。但在实践中,int和指针通常是相同的大小:处理器的位宽,因此几乎总是long int可以容纳指针。我相信有些系统无法使用,但我无法列举出来,而且我敢打赌你也不行。所以如果他决定使用long int(这在问题标题中),我想至少告诉他如何做到。 - Keith Irwin
你不认为我们应该教育他,让他明白为什么这种疯狂是不必要的吗? - Dan
1
实际上,他问如何做某事。我不知道他为什么要这样做,你也不知道。我们只知道很少有好的理由去这样做。你认为他一定是因为不知道更好的方法(他可能确实不知道),而你的工作就是告诉他不应该这样做以及原因。这很好。我不觉得我需要做所有这些,因为我不确定他是否真的不知道更好的方法,即使他不知道,有时候人们通过自己的错误学习得更好,而不是仅仅指出错误。 - Keith Irwin
1
先生们,请听我说。我知道这是一个奇怪的问题,但我使用它是因为这是用于在JNI库中桥接Ogg Vorbis库到Java的,以便我可以从Java应用程序中流式传输Vorbis声音。不可能直接从本地代码传递结构体到Java代码(显而易见的原因),所以我的方法是将指针本身作为整数值传递到Java程序中,然后在需要再次在本地代码中使用时将其传回。 - Knetic
显示剩余4条评论

3
其他人已经回答了你的问题,但是我想做一个更一般的评论。你提到了JNI;在这种情况下,你不需要使用long int,而是要用jlong(它将是一个typedef,可能是long int或long long int,具体取决于机器)。问题是long的大小取决于机器,会映射到不同的Java类型。当然,你指望jlong足够大以容纳指针,但由于jlong是64位的,所以在不久的将来(甚至更远的未来)似乎是一个安全的赌注,因为64位寻址已足够满足需求。
此外,我建议你借鉴Swig的思想,避免指针到整数的细微差别,可以使用以下代码:
jlong forJNI = 0;
*reinterpret_cast<DummyStructure*>( &forJNI ) = structure;
//  ...
structure2 = *reinterpret_cast<DummyStructure*>( &forJNI );

虽然不太优美,但是只要 sizeof(DummyStructure*) <= 64 就能保证在所有系统上都能工作(有一个警告)。

只需要确保关闭 strict aliasing 编译选项即可。(每次在指针和整数之间进行强制类型转换时都需要这样做。我认为,在编译器能够看到转换的情况下,不应该执行此操作,但某些编译器作者更喜欢有意打破代码,即使意图明确。)


1

长整型并不同于指针。为什么不直接这样做:

DummyStructure** point;

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

structure2 = *point;

问题可能是由于以下原因的组合:1)您没有解除引用指针。 structure2 是指向 structure 的指针,而 structure 本身也是一个指针。您需要执行以下操作:

structure2 = *((DummyStructure*)point);

但是除此之外,长整型并不等同于指针。这里可能还存在符号问题。


0
point = (long int)&structure;

这将获取 structure 的地址,它是一个 DummyStructure* 并将其分配给 point。因此,point 应该是一个双指针(指向指针的指针)。当您分配 structure2 时,应进行适当的类型转换。

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;

如果您的意图是使structure2指向与structure相同的内存位置,为什么不直接赋值,而要使用一个中间的long int **呢?

0
错误在于pointstructure的地址,而structure本身是指向DummyStructure的指针。为了使structure2指向与structure相同的东西,您需要取消引用point。现在先忽略所有长度、符号和类似的问题,

structure2 = *(DummyStructure**)point;

会修复您的代码。但为什么不直接:

structure2 = structure;

如果你真的想在某个通用的东西中持有一个指针,那就把它放在 void* 中。至少这是正确的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接