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

问题描述 投票:5回答:2

在(C和C ++)中,指向不同类型的don't necessarily have the same size。我本来希望void *必然是最大的,但它似乎甚至没有实际保证。

我的问题:如何确定指针(编译目标)平台上最大的指针大小?

注意:我指的是任何指针,包括指向类成员函数的指针;你可以通过&运营商获得的东西。我并不是指被称为“通俗”称为指针的实体,即不是unique_ptrshared_ptr等。

c++ pointers sizeof
2个回答
3
投票

C ++语言中有四种完全不相关的指针类型类:对象指针,函数指针,非静态数据成员指针和非静态成员函数指针。术语“指针”通常仅适用于对象和函数指针类型[basic.compound]/3

[...]除了指向静态成员的指针外,引用“指针”的文本不适用于指向成员的指针。 [...]

指向非静态成员的指针和指针实际上被视为两种完全独立的复合类型[basic.compound]/1(这是有道理的,因为非静态成员指针更像是相对偏移而不像实际地址)。

除了在对象和函数指针之间有条件支持的转换之外,其语义(如果支持的话)将是实现定义的[expr.reinterpret.cast]/8,则无法在这四类指针类型之间进行转换。

但是,该标准确实指定了对象指针[expr.reinterpret.cast]/7之间的可互换性,函数指针[expr.reinterpret.cast]/6之间的可互换性,数据成员指针[expr.reinterpret.cast]/10.2之间的可互换性,以及成员函数指针[expr.reinterpret.cast]/10.1之间的可互换性。

因此,虽然没有通用的指针类型,所有其他指针类型通常都与之相关,但是将任何对象指针强制转换为某个任意对象指针类型并返回它是明确定义的行为。将任何函数指针强制转换为某个任意函数指针类型并返回它是明确定义的行为。将任何数据成员指针强制转换为某些任意数据成员指针类型并返回,这是明确定义的行为。并且将任何成员函数指针强制转换为某些任意成员函数指针类型并返回它是明确定义的行为。所有这些不同类型的指针类型有一个共同点就是它们都是对象类型[basic.types]/8

虽然这并不严格保证,例如,所有成员函数指针类型的大小相同,但它确实隐式地确定某些成员函数指针类型的任何对象可以有效地用于存储任何成员函数指针值。可能仍然存在比其他成员函数指针类型更大的成员函数指针类型,但是它们不可能保存比其他函数更多的信息,因为标准要求与任何其他成员函数指针类型的转换不得丢失信息(原始值总是可以恢复)。相同的参数类似于所有其他类指针类型。

基于这一切,我认为在标准C ++中找到“最大指针类型”在技术上是不可能的。然而,虽然在技术上可能无法找到最大的指针类型本身,但基于上面的论证,绝对有可能找到可靠地存储任何指针类型值所需的存储量的上限。虽然这两者在技术上是不同的,但在实践中,第二个很可能几乎与第一个一样好(没有合理的编译器会随机地将大量填充位添加到某些指针类型的值表示中,因为这样做在技术上是合法的)。至少我很难想象除了存储指针值之外还有什么可能是你想要的那种信息。

例如,使用

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::*)();

你可以计算

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) });

或者只是使用

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>;

甚至

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

或以其纯粹的形式:

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

当存储到void*和从void (*)()转换时可以存储任何对象指针值的存储时,任何函数指针值都可以存储到dummy_t dummy_t::*和从void (dummy_t::*)()转换时,任何数据成员指针都可以在转换为来自play with it here和任何成员函数时存储当与void *进行强制转换时,可以存储指针。

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;

把它包装在一个类中的任务,该类负责处理任何指针类型的任意值的所有转换(不要忘记处理可能的cv资格),应留给读者练习,主要是因为我会我今晚真的很想睡个好觉......


4
投票

有3种不同类型的指针,可以有不同的大小:

  • 指针到对象
  • 功能指针
  • 成员函数指针

根据C ++ 17标准6.9.2.5,保证void *足够大以容纳每个指向对象的指针:

指向cv-qualified([basic.type.qualifier])或cv-unqualified void的指针可用于指向未知类型的对象。这样的指针应该能够保存任何对象指针。 cv void *类型的对象应具有与cv char *相同的表示和对齐要求。

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

应该做的工作。

编辑:C ++ 17标准6.9.2.3说

除了指向静态成员的指针外,引用“指针”的文本不适用于指向成员的指针。

所以,最大可能的指针是qazxswpoi或函数指针:

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.