【问题标题】:Why can't pointer fit variable of different type, even though sizeof is same?为什么即使 sizeof 相同,指针也不能适应不同类型的变量?
【发布时间】:2019-04-08 12:03:38
【问题描述】:

为什么任何指针的大小都是 4 或 8 字节,但它不能容纳任何不同的变量?尝试为双指针分配 int 指针值时出错。

int          *int_ptr{nullptr};
float        *float_ptr{nullptr};
double       *double_ptr{nullptr};
long double  *long_double_ptr{nullptr};
string       *string_ptr{nullptr};
vector<int>   *vector_ptr{nullptr};

cout << "sizeof int pointer is " << sizeof int_ptr;    //8 or 4
cout << "sizeof float pointer is " << sizeof float_ptr;    //8 or 4
cout << "sizeof double pointer is " << sizeof double_ptr;    //8 or 4
cout << "sizeof double double pointer is " << sizeof long_double_ptr;    //8 or 4
cout << "sizeof string pointer is " << sizeof string_ptr;    //8 or 4
cout << "sizeof vector int pointer is " << sizeof vector_ptr;  //8 or 4

double double_num{1020.7};
double_ptr = &int_ptr;      //cannot convert ‘int**’ to ‘double*’ in assignment

【问题讨论】:

  • 因为类型不仅仅是为了“拟合”一个尺寸。
  • 阅读Wikipedia article关于“类型系统”和What is Type safe?可能会有所帮助
  • 您是否打算写double_ptr = &amp;double_num
  • 假设你钓到的鱼和你的猫一样大,那么你的猫还是猫不是鱼……

标签: c++ pointers types casting strong-typing


【解决方案1】:

C++ 是一种静态类型语言。该语言通过拒绝不相关类型之间的任意转换来强制执行类型安全并保护您免受错误的影响。类型的含义并不能完全由大小单独描述。

如果地址包含int* 类型的对象,则int** 可以指向该对象。鉴于地址包含int* 类型的对象,它不可能还包含double 类型的对象,因此没有有意义的方法将其中一个指针转换为另一个。

【讨论】:

    【解决方案2】:

    指针是地址。 假设您有两个地址:

    1. 53大街
    2. 错转路85号

    第一个是两居室小房子的地址。 第二个是地址是一个豪宅,23间卧室,10间浴室,等等......

    你不能指望所有住在豪宅里的人都搬进小房子吗? 但猜猜怎么了?在邮局,他们的箱子大小是一样的! 他们就是这样工作的。他们只是告诉你在哪里可以找到你的变量。它们不是容器

    【讨论】:

    • 我不明白这是如何回答这个问题的。从您的示例中,可以(错误地,当然,但仍然可能)将地址 2 写在用于地址 1 的字母中。此外,正如您所说,指针不仅是地址,它们还包含其他类型信息。
    • 是的,如果指针与类型无关,那将是一个很好的例子,在你的类比中,没有什么能阻止我交换两个地址
    • 您可以通过以下方式解决此问题:您有一张带有屠夫广告的传单和一张带有面包店广告的传单。传单上写的地址只是地址,换了也能找到房子,但得不到你想要的,传单就没用了
    【解决方案3】:

    此代码是非法的,因为没有从 &amp;int_ptr 映射到 double_ptr"implicit conversion",其中“隐式转换”被定义为:

    在不接受该类型但接受其他类型T2的上下文中使用某种类型的表达式T1时执行;特别是:

    • 在调用以T2 为参数声明的函数时,将表达式用作参数时;
    • 当表达式用作操作数时,其运算符应为T2; 初始化T2 类型的新对象时,包括返回T2 的函数中的return 语句;
    • 在switch语句中使用表达式时(T2为整型);
    • 当表达式用于 if 语句或循环时(T2 是布尔值)。 仅当存在从T1T2 的明确隐式转换序列时,该程序才是格式正确的(编译)。

    I initially suggested 你使用reinterpret_cast 但这也行不通,因为在类型之间使用reinterpret_cast 的结果只有在类型的区别仅在于它们是否签名时才是合法的,类型被强制转换 tobyte*char*unsigned char*,或者类型是“相似的”,定义为:

    • 它们是同一类型;或
    • 它们都是指针,指向的类型相似;或
    • 它们都是指向同一个类的成员的指针,所指向的成员的类型相似;或
    • 它们都是相同大小的数组或都是未知边界的数组,并且数组元素类型相似。

    如您所见,这些情况都不适用于想要从int* int_ptr 的地址转换到double* double_ptr。我很难预测您在strongly typed language 中使用这种类型的演员的用例,但也许void* 是您正在寻找的?它可以指向或者一个有效的int**,在这种情况下,您可以像这样初始化它:const void* ptr = reinterpret_cast&lt;void*&gt;(&amp;int_ptr) 或一个有效的double*,在这种情况下,您可以像这样初始化它:@987654349 @。当然,要使用ptr,您需要一个变量来告诉您它包含的类型,例如:

    if(is_int) {
        // recover int** (reinterpret_cast<const int* const*>(ptr)) and operate on it
    } else {
        // recover double* (reinterpret_cast<const double*>(ptr)) and operate on it
    }
    

    Live Example

    在这一点上我应该承认这个答案有些做作。使用此代码的任何地方的更好解决方案很可能是模板。

    【讨论】:

    • reinterpret cast 会导致未定义的行为
    • @Caleth 根据实施情况,您是正确的。为了不误导,我继续输入了一些进一步的解释。
    • 不依赖。您正在打破严格的别名规则,这是未定义的行为。您看到的特定行为是您所期望的,这完全是巧合。
    • @Caleth 感谢您的 cmets。我实际上知道reinterpret_cast 可以从任何指针类型转换为另一种不是byte* 的类型......我想我只是在那里失控了一分钟。谢谢你把我带回来:J
    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    相关资源
    最近更新 更多