C99中固定大小的指针类型

C99中固定大小的指针类型,c,pointers,portability,c99,C,Pointers,Portability,C99,我想创建一个类型来存储指针。该类型应与C99兼容,并具有64位的固定宽度。我提出了几个备选方案,但它们似乎都有缺陷: 使用uint64\u t是不正确的,因为指针和整数之间的转换是实现定义的[,6.3.2.3] uinptr_t也似乎不在图片范围内,因为这种类型的宽度不是固定的,而且类型是可选的[7.18.1.4] 使用结构,例如 struct { #ifdef __LP64__ void* ptr; #else // if big endian the followi

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

  • 使用
    uint64\u t
    是不正确的,因为指针和整数之间的转换是实现定义的[,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;
    
    也不起作用,因为指针的大小不是固定的

我要查找的类型是否有任何与C99兼容的定义?

对象指针 存储对象指针的最佳类型是
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);
对象指针 存储对象指针的最佳类型是
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);

我不理解你反对使用带有填充的
void*
。同一类型的所有对象具有相同的大小。如果不同的对象指针类型具有不同的大小,这无关紧要,因为您可以将其转换为
void*
以将其存储在超级指针中

关于
uintpttr\u t
:如果不支持它,那么很可能是因为在特定平台上实际上没有办法做到这一点


因此您可以使用
uintptr\t
。要添加固定宽度要求,您可以先转换到
uintpttr\t
,然后再转换到
uint64\t
(如果您高兴地知道,当有人推出指针大于64位的系统时,您必须更改代码!)

我不理解您反对使用带填充的
void*
。同一类型的所有对象具有相同的大小。如果不同的对象指针类型具有不同的大小,这无关紧要,因为您可以将其转换为
void*
以将其存储在超级指针中

关于
uintpttr\u t
:如果不支持它,那么很可能是因为在特定平台上实际上没有办法做到这一点


因此您可以使用
uintptr\t
。要添加固定宽度要求,您可以转换到
uintpttr\t
,然后转换到
uint64\t
(如果您很高兴知道当有人推出指针大于64位的系统时,您必须更改代码!)

您无法以64位类型便携存储指针值。实现使用128位指针是完全合法的


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

如果一个实现没有不带填充位的64位无符号整数类型,那么它将根本不定义
uint64\u t
(例如,一个具有9位字节的系统将无法实现
uint64\u t
)。有一种类型
uint_至少64_t
,顾名思义,它保证至少64位宽;它在大多数系统上正好是64位,并且仅在
uint64\t
不存在的系统上才比64位宽

uintptr\u t
保证在不丢失信息的情况下保存转换后的
void*
值,但不能保证它存在——如果它不存在,则任何整数类型都不能在不丢失信息的情况下保存转换后的
void*
值。一致性实现不需要任何整数类型,它可以保存指针值而不丢失信息

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


根本没有一种100%可移植的方式来做你想做的事情。你只需要满足于99.9%的可移植性。如果您不关心函数指针,我建议使用
uint64\u t
(可能定义您自己的
typedef
,以明确您在做什么),并添加编译时或运行时检查,以确认
sizeof(void*)无法以64位类型移植存储指针值。实现使用128位指针是完全合法的


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

如果一个实现没有不带填充位的64位无符号整数类型,那么它将