我想创建一个存储指针的类型。该类型应与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兼容定义?
答案 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*
宏是非标准的。