【问题标题】:Casting long int as a struct pointer将 long int 转换为结构指针
【发布时间】:2011-12-12 08:15:12
【问题描述】:

我知道这是一个相当愚蠢的问题,但似乎没有多少谷歌搜索或代码排列有效。

我有一个这样定义的结构。

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;

我强调我已经尝试了所有可能的 ** 和 * 排列。我只是不明白。它要么不编译,要么编译,当它编译时,我最终得到结构2中包含的字段的看似随机的数字。我假设我以某种方式结束了一个不正确的内存位置,但是除了使用 & 之外,你还能如何获得它?

我有记忆位置,对吧?如何将结构设置到该位置?

编辑;我忘了提(以及随后的答案),但我打算用它来为 jni 包装 libvorbis。使用 jni 意味着我不能回传 libvorbis 所做的任何结构,但它的核心功能需要它们。因此,我的包装器将直接使用 vorbis 来制作结构,并将指向它们的指针传递回 java,这样当我需要用更多声音填充缓冲区时,我可以简单地从整数值重新引用结构对象指针。

【问题讨论】:

  • 请注意,您不应该从malloc(3) 转换返回值——只需#include <stdlib.h>,您将获得malloc(3) 原型,它允许编译器为您处理所有事情。这些转换可以隐藏编译器警告消息,提醒您代码中的错误。
  • 很可能long 不够长,无法保存指针值。使用(u)intptr_t、size_t 或long long 可能会获得更好的结果。
  • 出于好奇,你为什么要使用 long int 呢?
  • Alex,不应该涉及运气,因为 DummyStructure** 工作正常。
  • @KeithIrwin:由于这个问题被标记为jni,我猜他想将指针转换为可以作为句柄传递给Java应用程序的类型。

标签: c++ c java-native-interface


【解决方案1】:

你为什么试图将指针转换为整数并返回?只是为了学习、解决问题、解决一些(不为人知的)限制,还是什么?在这样的“普通”程序中做这件事是一件相当奇怪的事情,因为没有意义。

问题的一个可能原因是无法保证指针甚至适合long int。您可以通过添加此代码来检查:

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

如果打印的数字不同,这可能是造成问题的最大原因。

如果您使用的是 C99,则无论如何都应该使用#include <stdint.h>,然后使用intptr_t 类型而不是unsigned long 来保存指针。

【讨论】:

  • 如果long int 不足以容纳指针,则将long int 转换为指针类型不应该编译。
【解决方案2】:

structure 已经是一个指针,所以你不必在那里取地址:

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

【讨论】:

  • 如果long int 小于指针的大小,则第二次强制转换将不会编译。 (在现代机器上不太可能,但我曾在指针为 48 位但 long int 只有 32 位的系统上工作过。)
【解决方案3】:

structure 已经是一个指针。你只想做point = (long int) structure; (虽然,实际上,为什么涉及一个长整数,我不知道。只做structure2=structure; 要容易得多,因为structure 和structure2 是两个指针。)

当您执行&amp;structure 时,您将获得存储指针本身的内存位置,这就是它不是正确值的原因。你真的可能不想使用&amp;structure,除非它被传递到一个函数中,该函数将改变 DummyStructure structure 指向的函数。

【讨论】:

  • 这是个坏主意,因为 C 规范不保证长整数与指针的长度相同。
  • 当然这是个坏主意。整个问题是个坏主意。没有保证与指针长度相同的整数类型。但在实践中,整数和指针的大小通常相同:处理器的位宽,因此长整数几乎总是可以容纳指针。我敢肯定在某个地方有一些系统无法正常工作,但我不能说出其中一个,我敢打赌你也不能。因此,如果他决定使用 long int(在问题标题中),我想我至少会告诉他该怎么做。
  • 你认为我们不应该教育他为什么不需要这种精神错乱吗?
  • 真的,有人问他怎么做。我不知道他这样做的原因是什么,你也不知道。我们都知道这样做的充分理由很少。你觉得他一定会这样做,因为他不知道更好(他可能不知道),并且告诉他他不应该这样做以及为什么这样做是你的工作。没关系。我觉得我不需要做所有这些,因为我不确定他是否知道得更好,而且即使他不知道,嗯,有时候人们学会找出自己的错误比仅仅拥有错误更好指出。
  • 请,先生们。我知道这是一个奇怪的问题,我正在使用它,因为它旨在用于将 ogg vorbis 库桥接到 java 的 jni 库中,以便我可以从 java 应用程序中流式传输 vorbis 声音。不可能将结构直接从本机代码传递到 java 代码(原因很明显),所以我的办法是将指针本身作为整数值传递给 java 程序,然后在需要在本机代码中再次使用时将其传回。
【解决方案4】:

其他人已经回答了您的问题,但我想发表更笼统的评论。你提到了JNI;在这种情况下,您不需要long int,而是需要jlong(这将是long int 或long long int 的typedef,具体取决于机器。问题是long 将具有不同的大小, 取决于机器, 并将映射到不同的 Java 类型. 当然, 你指望jlong 足够大来容纳一个指针, 但由于jlong 是 64 位, 这看起来像对不久的将来(及以后——我认为 64 位寻址不够用)来说,这是一个安全的赌注。

另外,我建议你借鉴 Swig 的一个想法,并避免指针指向整数转换的微妙之处,使用类似以下内容:

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

这很丑陋,但保证对所有人都有效(有一点需要注意) sizeof(DummyStructure*) &lt;= 64.

请务必在关闭严格别名的情况下进行编译。 (你必须 每当您在指针和整数之间进行转换时,请执行此操作。恕我直言,你不应该 必须在转换对编译器可见的情况下,但有些 编译器编写者更喜欢故意破坏代码,即使当 意图很明确。)

【讨论】:

    【解决方案5】:

    长整数与指针不同。你为什么不这样做:

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

    问题可能是以下事实的结合:1)您没有取消引用点。 structure2 是指向 structure 的指针,而 structure 本身就是一个指针。你必须这样做:

    structure2 = *((DummyStructure*)point);
    

    但最重要的是,长整数与指针不同。这里可能还有一个签名问题。

    【讨论】:

      【解决方案6】:
      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 **。

      【讨论】:

        【解决方案7】:

        错误在于point 是structure 的地址,它本身就是一个指向DummyStructure 的指针。为了使structure2 指向与structure 相同的东西,您需要取消对point 的引用。暂时忽略所有长度、签名和类似问题,

        structure2 = *(DummyStructure**)point;
        

        会修复您的代码。但为什么不只是:

        structure2 = structure;
        

        如果您真的想将指针保存在通用的东西中,请将其保存在 void* 中。至少这是合适的尺寸。

        【讨论】:

          猜你喜欢
          • 2020-10-21
          • 1970-01-01
          • 1970-01-01
          • 2017-02-12
          • 2012-03-02
          • 2014-05-02
          • 2017-08-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多