C99中固定大小的指针类型

时间:2014-07-30 21:10:11

标签: c pointers portability c99

我想创建一个存储指针的类型。该类型应与C99兼容,并具有64位的固定宽度。我提出了几个替代方案,但它们看起来都有缺陷:

  • 使用uint64_t是不正确的,因为指针和整数之间的转换是实现定义的[C99 standard,6.3.2.3]。
  • uinptr_t似乎也不在图片中,因为此类型的宽度不固定且类型是可选的[7.18.1.4]。
  • 使用

    等结构
    struct {
      #ifdef __LP64__
        void* ptr;
      #else
        // if big endian the following two fields need to be flipped
        void* ptr;
        uint32_t padding; 
      #endif  
    } fixed_ptr_type;
    

    不起作用,因为指针的大小未固定even within the same implementation

是否有任何类型的C99兼容定义?

3 个答案:

答案 0 :(得分:4)

对象指针

存储对象指针的最佳类型是void *。任何对象指针都可以转换为void *然后再转回。

函数指针

void *不一定存储函数指针。但是,任何函数指针都可以转换为另一种类型的函数指针,因此您可以将它们存储为某种任意类型(例如void (*)(void))。

填充

我不知道为什么你需要你的指针类型有一个预定的大小,但你可以使用一个联合填充它们,并希望结果不是太大:

union fixed_ptr_type {
  void *p;
  char c[64/CHAR_BIT];
};

assert (CHAR_BIT * sizeof (union fixed_ptr_type) == 64);

答案 1 :(得分:2)

我不理解您对使用void *填充的反对意见。所有相同类型的对象都具有相同的大小。如果不同的对象指针类型具有不同的大小,那并不重要,因为您将其转换为void *以将其存储在超级指针中。

关于uintptr_t:如果不支持,则可能是因为实际上没有办法在特定平台上执行此操作。

所以你可以使用uintptr_t。要添加固定宽度要求,您可以转为uintptr_t,然后转为uint64_t(如果您对知道自己需要在有人发布时更改代码感到高兴指针大于64位的系统!)

答案 2 :(得分:2)

您无法以64位类型移植存储指针值。对于使用128位指针的实现来说,这是完全合法的。

如果您不介意丢失指向大于64位的系统的可移植性,您可能会使用uint64_t。指针类型到uint64_t的转换不能保证在不丢失信息的情况下正常工作,但它们几乎肯定会在指针不超过64位的任何合理系统上这样做。

如果实现没有填充位的64位无符号整数类型,那么根本不会定义uint64_t(例如,具有9位字节的系统将无法实现{{1} }})。有一种类型uint64_t,顾名思义,保证至少 64位宽;它在大多数系统上都是64位,仅在uint_least64_t不存在的系统上宽于64位。

uint64_t保证保留已转换的uintptr_t值而不会丢失信息,但不能保证存在 - 如果它不存在,那么 no 整数类型可以保存转换后的void*值,而不会丢失信息。一致的实现不一定需要任何整数类型,它可以保存指针值而不会丢失信息。

函数指针是另一回事。从函数指针到void*或任何整数类型的转换具有未定义的行为(因为标准没有说明行为应该是什么)。

没有100%可移植的方式去做你想做的事情。您只需要满足99.9%的便携性。如果您不关心函数指针,我建议使用void*(可能定义您自己的uint64_t以明确您正在做的事情)并添加编译 - 时间或运行时检查以确认typedef。这应该涵盖我曾经听过的每一个现有实施。

了解您的实际目标可能会有所帮助。为什么要存储指针不超过或少于64位?这解决了将它们存储在sizeof (void*) <= sizeof (uint64_t)个对象中无法解决的问题?

顺便提一下,您在问题中提到的void*宏是非标准的。