简体   繁体   English

如何确定平台上最大的指针大小?

[英]How do I determine the largest pointer size on my platform?

In (C and) C++, pointers to different types don't necessarily have the same size . 在(C和C ++)中,指向不同类型的指针不一定具有相同的大小 I would have hoped void * is necessarily the largest, but it seems not even this is actually guaranteed. 我希望void *必然是最大的,但看起来甚至没有实际保证。

My question: How can I determine what the largest size of a pointer is on my (compilation target) platform? 我的问题:如何确定指针(编译目标)平台上最大的指针大小?

Note: I mean any pointer, including pointers to class member functions; 注意:我指的是任何指针,包括指向类成员函数的指针; things you can get with the & operator. 使用&运算符可以获得的东西。 I don't mean entities which are "colloquially" known as pointers, ie not unique_ptr 's or shared_ptr 's and such. 我并不是指“通俗地”称为指针的实体,即不是unique_ptrshared_ptr等。

There are 3 different types of pointers, which can have a different size: 有3种不同类型的指针,可以有不同的大小:

  • pointer-to-object 指针到对象
  • function pointer 功能指针
  • member function pointer 成员函数指针

A void * is guaranteed to be large enough to hold every pointer-to-object according to the C++17 Standard 6.9.2.5: 根据C ++ 17标准6.9.2.5, void *保证足够大以容纳每个指向对象的指针:

A pointer to cv-qualified ([basic.type.qualifier]) or cv-unqualified void can be used to point to objects of unknown type. 指向cv-qualified([basic.type.qualifier])或cv-unqualified void的指针可用于指向未知类型的对象。 Such a pointer shall be able to hold any object pointer. 这样的指针应该能够保存任何对象指针。 An object of type cv void* shall have the same representation and alignment requirements as cv char*. cv void *类型的对象应具有与cv char *相同的表示和对齐要求。

class A;

typedef void (A::*a_func_ptr)(void);
typedef void (*func_ptr)(void);

size_t a = sizeof(a_func_ptr), b = sizeof(func_ptr), c = sizeof(void*);

std::cout << std::max(a, std::max(b, c)) << std::endl;

should do the job. 应该做的工作。

edit: The C++17 Standard 6.9.2.3 says 编辑:C ++ 17标准6.9.2.3说

Except for pointers to static members, text referring to “pointers” does not apply to pointers to members. 除了指向静态成员的指针外,引用“指针”的文本不适用于指向成员的指针。

So, the largest possible pointer is either a void * or a function pointer: 因此,最大可能的指针是void *或函数指针:

std::cout << std::max(sizeof(void*), sizeof(void(*)(void))) << std::endl;

There are four completely unrelated classes of pointer types in the C++ language: object pointers, function pointers, non-static data member pointers, and non-static member function pointers. C ++语言中有四种完全不相关的指针类型类:对象指针,函数指针,非静态数据成员指针和非静态成员函数指针。 The term "pointer" generally only applies to object and function pointer types [basic.compound]/3 : 术语“指针”通常仅适用于对象和函数指针类型[basic.compound] / 3

[…] Except for pointers to static members, text referring to “pointers” does not apply to pointers to members. [...]除了指向静态成员的指针外,引用“指针”的文本不适用于指向成员的指针。 […] [...]

Pointers and pointers to non-static members are actually treated as two completely separate kinds of compound types altogether [basic.compound]/1 (which makes sense since non-static member pointers are more like relative offsets and less like actual addresses). 指向非静态成员的指针和指针实际上被视为两个完全独立的复合类型[basic.compound] / 1 (这是有道理的,因为非静态成员指针更像是相对偏移而不像实际地址)。

Except for a conditionally-supported conversion between object and function pointers, the semantics of which (if supported at all) will be implementation-defined [expr.reinterpret.cast]/8 , there is no way to convert between these four classes of pointer types. 除了有条件支持的对象和函数指针之间的转换之外,其语义(如果支持的话)将是实现定义的[expr.reinterpret.cast] / 8 ,没有办法在这四类指针之间进行转换类型。

However, the standard does specify interconvertibility amongst object pointers [expr.reinterpret.cast]/7 , interconvertibility amongst function pointers [expr.reinterpret.cast]/6 , interconvertiblity amongst data member pointers [expr.reinterpret.cast]/10.2 , and interconvertibility amongst member function pointers [expr.reinterpret.cast]/10.1 . 但是,该标准确实指定了对象指针之间的可互换性[expr.reinterpret.cast] / 7 ,函数指针之间的可互换性[expr.reinterpret.cast] / 6 ,数据成员指针之间的互换性[expr.reinterpret.cast] /10.2 ,以及成员函数指针之间的可互换性[expr.reinterpret.cast] /10.1

As a result, while there is no common pointer type that all other pointer types are related to in general, it is well-defined behavior to cast any object pointer to some arbitrary object pointer type and back. 因此,虽然没有通用的指针类型,所有其他指针类型通常都与之相关,但是将任何对象指针强制转换为某个任意对象指针类型并返回它是明确定义的行为。 It is well-defined behavior to cast any function pointer to some arbitrary function pointer type and back. 将任何函数指针强制转换为某个任意函数指针类型并返回它是明确定义的行为。 It is well-defined behavior to cast any data member pointer to some arbitrary data member pointer type and back. 将任何数据成员指针强制转换为某些任意数据成员指针类型并返回,这是明确定义的行为。 And it is well-defined behavior to cast any member function pointer to some arbitrary member function pointer type and back. 并且将任何成员函数指针强制转换为某些任意成员函数指针类型并返回它是明确定义的行为。 And one thing all these different classes of pointer types have in common is that they're all object types [basic.types]/8 . 所有这些不同类型的指针类型有一个共同点就是它们都是对象类型[basic.types] / 8

While this does not strictly guarantee that, eg, all member function pointer types are the same size, it does implicitly establish that any object of some member function pointer type can effectively be used to store any member function pointer value. 虽然这并不严格保证,例如,所有成员函数指针类型都是相同的大小,但它确实隐式地确定某些成员函数指针类型的任何对象都可以有效地用于存储任何成员函数指针值。 There may still be member function pointer types larger than others, but they could not possibly hold more information than others since the standard requires that the conversion to and from any other member function pointer type must not lose information (the original value can always be restored). 可能仍然存在比其他成员函数指针类型更大的成员函数指针类型,但是它们不可能保存比其他函数更多的信息,因为标准要求与任何其他成员函数指针类型的转换不得丢失信息(原始值总是可以恢复)。 The same argument works analogously for all the other classes of pointer types. 相同的参数类似于所有其他类指针类型。

Based on all this, I would argue that it's technically impossible to find "the largest pointer type" in standard C++. 基于这一切,我认为在标准C ++中找到“最大指针类型”在技术上是不可能的。 However, while it may technically be impossible to find the largest pointer type itself, based on the argument above, it is definitely possible to find an upper bound for the amount of storage needed to reliably store any value of pointer type. 然而,虽然在技术上可能无法找到最大的指针类型本身,但基于上面的论证,绝对有可能找到可靠地存储任何指针类型值所需的存储量的上限。 While those two are technically different things, in practice, the second one is most likely almost as good as the first (no reasonable compiler will just randomly add lots of padding bits to the value representation of some pointer type just because doing so is technically legal). 虽然这两者在技术上是不同的,但在实践中,第二个很可能几乎与第一个一样好(没有合理的编译器会随机地将大量填充位添加到某些指针类型的值表示中,因为这样做在技术上是合法的)。 At least I'm having a hard time imagining what else than store pointer values you could possibly be wanting to do with the kind of information you're asking for. 至少我很难想象除了存储指针值之外还有什么可能是你想要的那种信息。

Using, for example 例如,使用

using generic_obj_ptr = void*;
using generic_fun_ptr = void (*)();

class dummy_t;
using generic_dat_mem_ptr = dummy_t dummy_t::*;
using generic_mem_fun_ptr = void (dummy_t::*)();

you can compute 你可以计算

auto obj_ptr_size = sizeof(generic_obj_ptr_t);
auto fun_ptr_size = sizeof(generic_fun_ptr_t);
auto dat_mem_ptr_size = sizeof(generic_dat_mem_ptr_t);
auto mem_fun_size = sizeof(generic_mem_fun_ptr_t);

auto max_ptr_size = std::max({ sizeof(generic_obj_ptr_t), sizeof(generic_fun_ptr_t), sizeof(generic_dat_mem_ptr_t), sizeof(generic_mem_fun_ptr_t) });
auto max_ptr_align = std::max({ alignof(generic_obj_ptr_t), alignof(generic_fun_ptr_t), alignof(generic_dat_mem_ptr_t), alignof(generic_mem_fun_ptr_t) });

or just use 或者只是使用

using ptr_storage_t = std::aligned_union<0U, generic_obj_ptr_t, generic_fun_ptr_t, generic_dat_mem_ptr_t, generic_mem_fun_ptr_t>;

or even 甚至

using any_ptr_t = std::variant<generic_obj_ptr_t, generic_fun_ptr_t, generic_dat_mem_ptr_t, generic_mem_fun_ptr_t>;

or in its pure form: 或以其纯粹的形式:

using any_ptr_t = std::variant<void*, void (*)(), dummy_t dummy_t::*, void (dummy_t::*)()>;

as storage in which any object pointer value can be stored when cast to and from void* , any function pointer value can be stored when cast to and from void (*)() , any data member pointer can be stored when cast to and from dummy_t dummy_t::* , and any member function pointer can be stored when cast to and from void (dummy_t::*)() . 作为在转换为void*时可以存储任何对象指针值的存储器,当转换为void (*)() ,可以存储任何函数指针值,任何数据成员指针都可以在转换为存储时存储dummy_t dummy_t::* ,并且当与void (dummy_t::*)()时,可以存储任何成员函数指针。

play with it here 在这玩吧

The task of wrapping this in a class that takes care of all the casting for storing arbitrary values of any pointer type (don't forget to deal with possible cv qualification), shall be left as an exercise for the reader, mainly because I would really like to sleep well tonight… 把它包装在一个类中的任务,该类负责处理任何指针类型的任意值的所有转换(不要忘记处理可能的cv资格),应留给读者练习,主要是因为我会我今晚真的很想睡个好觉......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何确定文件 (Windows) 上无缓冲 IO 的扇区大小? - How do I determine the sector size for unbuffered IO on a file (Windows)? 您如何确定由“ std :: map”创建的,与“ boost :: pool_allocator”一起使用的节点的大小(以跨平台方式)? - How do you determine the size of the nodes created by a 'std::map' for use with 'boost::pool_allocator' (in a cross-platform way)? 如何确定阵列的大小? - How do I fix the size of my array? C ++在创建指针时如何使用变量作为指针的大小? - C++ How do I use a variable for the size of the pointer when creating a pointer? 如何安全,明智地确定指针是否指向指定缓冲区的某处? - How do I safely and sensibly determine whether a pointer points somewhere into a specified buffer? 如何找到两个整数类型中最大的(大小)? - How can I find the largest (in size) of two integer types? 如何重置指向特定数组位置的指针? - How do I reset my pointer to a specific array location? 如何避免插入函数中的指针无效? - How do I avoid pointer invalidation in my insert function? 如何代表指向我的地址空间开头的指针? - How do I represent a pointer to the beginning of my address space? 如何使程序确定最大的用户输入 - How to make program determine largest user input
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM